Add skstd::optional::emplace.

Change-Id: I178ae881191e8ed7ce5399e806838a44d2358e31
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/442319
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/include/private/SkTOptional.h b/include/private/SkTOptional.h
index 452a190..f610493 100644
--- a/include/private/SkTOptional.h
+++ b/include/private/SkTOptional.h
@@ -65,7 +65,7 @@
     template<typename... Args>
     optional(Args&&... args) {
         fHasValue = true;
-        new(&fPayload.fValue) T(std::forward<Args...>(args...));
+        new(&fPayload.fValue) T(std::forward<Args>(args)...);
     }
 
     ~optional() {
@@ -112,6 +112,22 @@
         return *this;
     }
 
+    template<typename... Args>
+    optional& emplace(Args&&... args) {
+        this->reset();
+        fHasValue = true;
+        new(&fPayload.fValue) T(std::forward<Args>(args)...);
+        return *this;
+    }
+
+    template<typename U, typename... Args>
+    optional& emplace(std::initializer_list<U> il, Args&&... args) {
+        this->reset();
+        fHasValue = true;
+        new(&fPayload.fValue) T(il, std::forward<Args>(args)...);
+        return *this;
+    }
+
     // Assignment to nullopt is the same as reset().
     optional& operator=(nullopt_t) {
         this->reset();
diff --git a/tests/SkTOptionalTest.cpp b/tests/SkTOptionalTest.cpp
index 2936869..4f8c0b7 100644
--- a/tests/SkTOptionalTest.cpp
+++ b/tests/SkTOptionalTest.cpp
@@ -269,6 +269,27 @@
     REPORTER_ASSERT(r, !o);
 }
 
+DEF_TEST(SkTOptionalEmplace, r) {
+    skstd::optional<std::vector<int>> o;
+    REPORTER_ASSERT(r, !o);
+
+    // Emplace with the no-argument constructor
+    o.emplace();
+    REPORTER_ASSERT(r, o.has_value());
+    REPORTER_ASSERT(r, o->empty());
+
+    // Emplace with the initializer-list constructor
+    o.emplace({1, 2, 3});
+    REPORTER_ASSERT(r, o.has_value());
+    REPORTER_ASSERT(r, (*o == std::vector<int>{1, 2, 3}));
+
+    // Emplace with a normal constructor
+    std::vector<int> otherVec = {4, 5, 6};
+    o.emplace(otherVec.begin(), otherVec.end());
+    REPORTER_ASSERT(r, o.has_value());
+    REPORTER_ASSERT(r, (*o == std::vector<int>{4, 5, 6}));
+}
+
 DEF_TEST(SkTOptionalNoDefaultConstructor, r) {
     class NoDefaultConstructor {
     public: