Allow conversion from a type T to itself
authorSarang Masti <mssarang@fb.com>
Mon, 29 Dec 2014 22:39:03 +0000 (14:39 -0800)
committerAjit Banerjee <ajitb@fb.com>
Wed, 7 Jan 2015 20:24:35 +0000 (12:24 -0800)
Summary: same as title

Test Plan: - fbconfig -r folly && fbmake runtests

Reviewed By: andrei.alexandrescu@fb.com

Subscribers: folly-diffs@

FB internal diff: D1754577

Signature: t1:1754577:1419618119:4c1a59cd19b23de9a9f6574341944e5e80530d62

folly/Conv.h
folly/test/ConvTest.cpp

index def3d872b0e6541ffd75c90bfc86c2c038bb8202..4d6fb0dd8398aa9dbfcd5a7064082967eb6f3009 100644 (file)
 
 namespace folly {
 
+/**
+ * The identity conversion function.
+ * to<T>(T) returns itself for all types T.
+ */
+template <class Tgt, class Src>
+typename std::enable_if<std::is_same<Tgt, Src>::value, Tgt>::type
+to(const Src & value) {
+  return value;
+}
+
+template <class Tgt, class Src>
+typename std::enable_if<std::is_same<Tgt, Src>::value, Tgt>::type
+to(Src && value) {
+  return std::move(value);
+}
+
 /*******************************************************************************
  * Integral to integral
  ******************************************************************************/
@@ -64,7 +80,9 @@ namespace folly {
  */
 template <class Tgt, class Src>
 typename std::enable_if<
-  std::is_integral<Src>::value && std::is_integral<Tgt>::value,
+  std::is_integral<Src>::value
+  && std::is_integral<Tgt>::value
+  && !std::is_same<Tgt, Src>::value,
   Tgt>::type
 to(const Src & value) {
   /* static */ if (std::numeric_limits<Tgt>::max()
@@ -90,7 +108,9 @@ to(const Src & value) {
 
 template <class Tgt, class Src>
 typename std::enable_if<
-  std::is_floating_point<Tgt>::value && std::is_floating_point<Src>::value,
+  std::is_floating_point<Tgt>::value
+  && std::is_floating_point<Src>::value
+  && !std::is_same<Tgt, Src>::value,
   Tgt>::type
 to(const Src & value) {
   /* static */ if (std::numeric_limits<Tgt>::max() <
@@ -819,20 +839,6 @@ toAppendDelimFit(const Delimiter& delim, const Ts&... vs) {
 template <class De, class Ts>
 void toAppendDelimFit(const De&, const Ts&) {}
 
-/**
- * to<SomeString>(SomeString str) or to<StringPiece>(StringPiece str) returns
- * itself. As both std::string and folly::fbstring use Copy-on-Write, it's much
- * more efficient by avoiding copying the underlying char array.
- */
-template <class Tgt, class Src>
-typename std::enable_if<
-  (IsSomeString<Tgt>::value
-   || std::is_same<Tgt, folly::StringPiece>::value)
-  && std::is_same<Tgt, Src>::value, Tgt>::type
-to(const Src & value) {
-  return value;
-}
-
 /**
  * to<SomeString>(v1, v2, ...) uses toAppend() (see below) as back-end
  * for all types.
@@ -1403,13 +1409,15 @@ to(const Src & value) {
 // std::underlying_type became available by gcc 4.7.0
 
 template <class Tgt, class Src>
-typename std::enable_if<std::is_enum<Src>::value, Tgt>::type
+typename std::enable_if<
+  std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
 to(const Src & value) {
   return to<Tgt>(static_cast<typename std::underlying_type<Src>::type>(value));
 }
 
 template <class Tgt, class Src>
-typename std::enable_if<std::is_enum<Tgt>::value, Tgt>::type
+typename std::enable_if<
+  std::is_enum<Tgt>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
 to(const Src & value) {
   return static_cast<Tgt>(to<typename std::underlying_type<Tgt>::type>(value));
 }
@@ -1417,7 +1425,8 @@ to(const Src & value) {
 #else
 
 template <class Tgt, class Src>
-typename std::enable_if<std::is_enum<Src>::value, Tgt>::type
+typename std::enable_if<
+  std::is_enum<Src>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
 to(const Src & value) {
   /* static */ if (Src(-1) < 0) {
     /* static */ if (sizeof(Src) <= sizeof(int)) {
@@ -1435,7 +1444,8 @@ to(const Src & value) {
 }
 
 template <class Tgt, class Src>
-typename std::enable_if<std::is_enum<Tgt>::value, Tgt>::type
+typename std::enable_if<
+  std::is_enum<Tgt>::value && !std::is_same<Src, Tgt>::value, Tgt>::type
 to(const Src & value) {
   /* static */ if (Tgt(-1) < 0) {
     /* static */ if (sizeof(Tgt) <= sizeof(int)) {
index 31cd9edad5cffe0b05a9428001815f8ebbfbed8e..ad44421bb011f65187a4f29224c1bcf497c33919 100644 (file)
@@ -34,6 +34,36 @@ static uint32_t u32;
 static int64_t s64;
 static uint64_t u64;
 
+// Test to<T>(T)
+TEST(Conv, Type2Type) {
+  int intV = 42;
+  EXPECT_EQ(to<int>(intV), 42);
+
+  float floatV = 4.2;
+  EXPECT_EQ(to<float>(floatV), 4.2f);
+
+  double doubleV = 0.42;
+  EXPECT_EQ(to<double>(doubleV), 0.42);
+
+  std::string stringV = "StdString";
+  EXPECT_EQ(to<std::string>(stringV), "StdString");
+
+  folly::fbstring fbStrV = "FBString";
+  EXPECT_EQ(to<folly::fbstring>(fbStrV), "FBString");
+
+  folly::StringPiece spV("StringPiece");
+  EXPECT_EQ(to<folly::StringPiece>(spV), "StringPiece");
+
+  // Rvalues
+  EXPECT_EQ(to<int>(42), 42);
+  EXPECT_EQ(to<float>(4.2f), 4.2f);
+  EXPECT_EQ(to<double>(.42), .42);
+  EXPECT_EQ(to<std::string>(std::string("Hello")), "Hello");
+  EXPECT_EQ(to<folly::fbstring>(folly::fbstring("hello")), "hello");
+  EXPECT_EQ(to<folly::StringPiece>(folly::StringPiece("Forty Two")),
+            "Forty Two");
+}
+
 TEST(Conv, Integral2Integral) {
   // Same size, different signs
   s64 = numeric_limits<uint8_t>::max();