Add Optional::value_or
authorTudor Bosman <tudorb@fb.com>
Sat, 16 Aug 2014 22:09:20 +0000 (15:09 -0700)
committerSara Golemon <sgolemon@fb.com>
Tue, 9 Sep 2014 21:22:22 +0000 (14:22 -0700)
Summary:
Common pattern: a function returns Optional<X>, indicating whether some X was
present or not; you want a default value if the X was not present. Requires
that X is copiable.

Test Plan: optional_test (test added)

Reviewed By: tjackson@fb.com

Subscribers: aalexandre, fjargsto, jhj, ntv, lesha, kma

FB internal diff: D1502397

folly/Optional.h
folly/test/OptionalTest.cpp

index eb8de160c8903d47bda5757c4e28b783bd402ae1..eea1957ca446e19b33750d814154bcbe027d4116 100644 (file)
@@ -225,6 +225,17 @@ class Optional {
   const Value* operator->() const { return &value(); }
         Value* operator->()       { return &value(); }
 
+  // Return a copy of the value if set, or a given default if not.
+  template <class U>
+  Value value_or(U&& dflt) const& {
+    return hasValue_ ? value_ : std::forward<U>(dflt);
+  }
+
+  template <class U>
+  Value value_or(U&& dflt) && {
+    return hasValue_ ? std::move(value_) : std::forward<U>(dflt);
+  }
+
  private:
   template<class... Args>
   void construct(Args&&... args) {
index 79968d013f3b439b8607105414c9486b5497187b..efea777f2baef9a7d68d9ca58d530433f58a1b9e 100644 (file)
@@ -97,15 +97,49 @@ TEST(Optional, Const) {
 TEST(Optional, Simple) {
   Optional<int> opt;
   EXPECT_FALSE(bool(opt));
+  EXPECT_EQ(42, opt.value_or(42));
   opt = 4;
   EXPECT_TRUE(bool(opt));
   EXPECT_EQ(4, *opt);
+  EXPECT_EQ(4, opt.value_or(42));
   opt = 5;
   EXPECT_EQ(5, *opt);
   opt.clear();
   EXPECT_FALSE(bool(opt));
 }
 
+TEST(Optional, value_or_rvalue_arg) {
+  Optional<std::string> opt;
+  std::string dflt = "hello";
+  EXPECT_EQ("hello", opt.value_or(dflt));
+  EXPECT_EQ("hello", dflt);
+  EXPECT_EQ("hello", opt.value_or(std::move(dflt)));
+  EXPECT_EQ("", dflt);
+  EXPECT_EQ("world", opt.value_or("world"));
+
+  dflt = "hello";
+  // Make sure that the const overload works on const objects
+  const auto& optc = opt;
+  EXPECT_EQ("hello", optc.value_or(dflt));
+  EXPECT_EQ("hello", dflt);
+  EXPECT_EQ("hello", optc.value_or(std::move(dflt)));
+  EXPECT_EQ("", dflt);
+  EXPECT_EQ("world", optc.value_or("world"));
+
+  dflt = "hello";
+  opt = "meow";
+  EXPECT_EQ("meow", opt.value_or(dflt));
+  EXPECT_EQ("hello", dflt);
+  EXPECT_EQ("meow", opt.value_or(std::move(dflt)));
+  EXPECT_EQ("hello", dflt);  // only moved if used
+}
+
+TEST(Optional, value_or_noncopyable) {
+  Optional<std::unique_ptr<int>> opt;
+  std::unique_ptr<int> dflt(new int(42));
+  EXPECT_EQ(42, *std::move(opt).value_or(std::move(dflt)));
+}
+
 TEST(Optional, EmptyConstruct) {
   Optional<int> opt;
   EXPECT_FALSE(bool(opt));