]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Make Optional<bool> trivially copyable (#1188)
authorAlex Rousskov <rousskov@measurement-factory.com>
Thu, 1 Dec 2022 05:49:57 +0000 (05:49 +0000)
committerSquid Anubis <squid-anubis@squid-cache.org>
Thu, 1 Dec 2022 08:04:30 +0000 (08:04 +0000)
    ipc/TypedMsgHdr.h: static assertion failed: putPod() used for a POD
    ActionParams.cc:44: required from here [with Pod = RequestFlags]

The known XXX in Optional destructor has started to bite us because
pending changes expose memcpy(3)-based IPC serialization code to
Optional<bool> flags. It is possible to mimic standard std::optional
implementations, avoiding that XXX, but that requires rather
sophisticated C++ tricks with placement new() and such. Specializing the
whole Optional is a better alternative for this _temporary_ class IMO.

src/base/Optional.h

index a803d30d8cf85b5cbeacdfcdeaac8f533890f0b5..1c153b99c849f87c0d7c0a96e76576c8abc018f2 100644 (file)
@@ -122,6 +122,53 @@ private:
     bool hasValue_ = false;
 };
 
+/// Specialization to make Optional<bool> trivially-copyable. XXX: Keep this
+/// temporary (until we switch to C++17 std::optional) hack in sync with the
+/// generic Optional above, copying generic methods where possible.
+template <>
+class Optional<bool>
+{
+public:
+    using Value = bool;
+
+    constexpr Optional() noexcept = default;
+    constexpr explicit Optional(const Value &v): value_(v), hasValue_(true) {}
+
+    constexpr explicit operator bool() const noexcept { return hasValue_; }
+    constexpr bool has_value() const noexcept { return hasValue_; }
+
+    const Value &value() const &
+    {
+        if (!hasValue_)
+            throw BadOptionalAccess();
+        return value_;
+    }
+
+    template <class Other>
+    constexpr Value value_or(Other &&defaultValue) const &
+    {
+        return hasValue_ ? value_ : static_cast<Value>(std::forward<Other>(defaultValue));
+    }
+
+    template <class Other = Value>
+    Optional &operator =(Other &&otherValue)
+    {
+        value_ = std::forward<Other>(otherValue);
+        hasValue_ = true;
+        return *this;
+    }
+
+    void reset() {
+        if (hasValue_) {
+            hasValue_ = false;
+        }
+    }
+
+private:
+    Value value_ = false;
+    bool hasValue_ = false;
+};
+
 template <typename Value>
 inline
 std::ostream &operator <<(std::ostream &os, const Optional<Value> &opt)