ConditionallyExistent<typename>
authorYedidya Feldblum <yfeldblum@fb.com>
Fri, 5 Feb 2016 20:27:56 +0000 (12:27 -0800)
committerfacebook-github-bot-0 <folly-bot@fb.com>
Fri, 5 Feb 2016 21:20:24 +0000 (13:20 -0800)
Summary:
[Folly] `ConditionallyExistent<typename>`.

For when we need extra member fields in dbg builds, but want to save the space in opt builds. Or other situations along similar lines, but with perhaps another the statically-known condition.

Conditional compilation can have some nasty side-effects. Best to avoid it. Let the compiler see everything, rather than having the preprocessor ruin our day. Let the optimizer remove code that will never be called, after the compiler has seen it. Let us have a single AST in our source file, not one AST for dbg and one for opt, or other statically-known conditions.

Reviewed By: andriigrynenko

Differential Revision: D2879397

fb-gh-sync-id: d631141a984eebd46674f27a40a97f670eb33f54

folly/ConditionallyExistent.h [new file with mode: 0644]
folly/Makefile.am
folly/Portability.h
folly/test/ConditionallyExistentTest.cpp [new file with mode: 0644]
folly/test/Makefile.am

diff --git a/folly/ConditionallyExistent.h b/folly/ConditionallyExistent.h
new file mode 100644 (file)
index 0000000..c40dff1
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <glog/logging.h>
+#include <folly/Portability.h>
+
+namespace folly {
+
+template <typename T, bool Debug>
+class ConditionallyExistent;
+
+template <typename T>
+class ConditionallyExistent<T, false> {
+ public:
+  static constexpr bool present() { return false; }
+  explicit ConditionallyExistent(const T&) {}
+  explicit ConditionallyExistent(T&&) {}
+  ConditionallyExistent(const ConditionallyExistent&) = delete;
+  ConditionallyExistent(ConditionallyExistent&&) = delete;
+  ConditionallyExistent& operator=(const ConditionallyExistent&) = delete;
+  ConditionallyExistent& operator=(ConditionallyExistent&&) = delete;
+  template <typename F>
+  void with(const F&&) {}
+};
+
+template <typename T>
+class ConditionallyExistent<T, true> {
+ public:
+  static constexpr bool present() { return true; }
+  explicit ConditionallyExistent(const T& v) : value_(v) {}
+  explicit ConditionallyExistent(T&& v) : value_(std::move(v)) {}
+  ConditionallyExistent(const ConditionallyExistent&) = delete;
+  ConditionallyExistent(ConditionallyExistent&&) = delete;
+  ConditionallyExistent& operator=(const ConditionallyExistent&) = delete;
+  ConditionallyExistent& operator=(ConditionallyExistent&&) = delete;
+  template <typename F>
+  void with(F&& f) {
+    f(value_);
+  }
+
+ private:
+  T value_;
+};
+
+template <typename T>
+using ExistentIfDebug = ConditionallyExistent<T, kIsDebug>;
+}
index 1cf593377a7a548b8ec7ce861d32b3a01e282b47..1440a07b856739adbc11de7366b9b0e0a72e051f 100644 (file)
@@ -263,6 +263,7 @@ nobase_follyinclude_HEADERS = \
        PicoSpinLock.h \
        Portability.h \
        portability/Syscall.h \
+       ConditionallyExistent.h \
        Preprocessor.h \
        ProducerConsumerQueue.h \
        Random.h \
index 5054afd8424a3271e04b59e7611f3234eab80b8a..b1faa45c285fa7ddec19bb434a2686d700343dda 100644 (file)
@@ -334,6 +334,15 @@ typedef SSIZE_T ssize_t;
 
 #endif
 
+// Debug
+namespace folly {
+#ifdef NDEBUG
+constexpr auto kIsDebug = false;
+#else
+constexpr auto kIsDebug = true;
+#endif
+}
+
 // Endianness
 namespace folly {
 #ifdef _MSC_VER
diff --git a/folly/test/ConditionallyExistentTest.cpp b/folly/test/ConditionallyExistentTest.cpp
new file mode 100644 (file)
index 0000000..b198e00
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/ConditionallyExistent.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace folly;
+
+namespace {
+
+class ConditionallyExistentTest : public testing::Test {};
+}
+
+TEST_F(ConditionallyExistentTest, WhenConditionFalse) {
+  folly::ConditionallyExistent<string, false> foobar("hello world");
+  EXPECT_FALSE(foobar.present());
+  bool called = false;
+  foobar.with([&](const string&) { called = true; });
+  EXPECT_FALSE(called);
+}
+
+TEST_F(ConditionallyExistentTest, WhenConditionTrue) {
+  folly::ConditionallyExistent<string, true> foobar("hello world");
+  EXPECT_TRUE(foobar.present());
+  bool called = false;
+  foobar.with([&](const string&) { called = true; });
+  EXPECT_TRUE(called);
+}
index 641c98cb6898700825072c71dad065f4c3a797f8..8c305dd7008704cedd0074de74502115799928ae 100644 (file)
@@ -159,6 +159,10 @@ string_test_SOURCES = StringTest.cpp
 string_test_LDADD = libfollytestmain.la
 TESTS += string_test
 
+conditionally_existent_test_SOURCES = ConditionallyExistent.cpp
+conditionally_existent_test_LDADD = libfollytestmain.la
+TESTS += conditionally_existent_test
+
 producer_consumer_queue_test_SOURCES = ProducerConsumerQueueTest.cpp
 producer_consumer_queue_test_LDADD = libfollytestmain.la
 TESTS += producer_consumer_queue_test