FixedString gets comparisons with folly::Range and hence with std::string
authorEric Niebler <eniebler@fb.com>
Fri, 5 May 2017 21:10:47 +0000 (14:10 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 5 May 2017 21:20:47 +0000 (14:20 -0700)
Summary: It should be possible to perform simple comparison operations between a FixedString and a std::string. By adding asymmetric comparison operators with FixedString and Range, we make FixedString comparable with anything convertible to Range, including std::string.

Reviewed By: yfeldblum

Differential Revision: D5007704

fbshipit-source-id: fee89d8807ac2d5378eec0d0a51eb8684976a271

folly/FixedString.h
folly/test/FixedStringTest.cpp

index ee0528271b2d5b5d1fd3ed01725f0b9d9c8c7c06..a18838b902e963bd83ab1d99febee03c746338cc 100644 (file)
@@ -28,6 +28,7 @@
 #include <type_traits>
 #include <utility>
 
+#include <folly/Range.h>
 #include <folly/Utility.h>
 #include <folly/portability/BitsFunctexcept.h>
 #include <folly/portability/Constexpr.h>
@@ -436,10 +437,6 @@ struct ReverseIterator {
 } // namespace fixedstring
 } // namespace detail
 
-// Defined in folly/Range.h
-template <class Iter>
-class Range;
-
 // Defined in folly/Hash.h
 std::uint32_t hsieh_hash32_buf(const void* buf, std::size_t len);
 
@@ -1606,6 +1603,13 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return compare(0u, size_, that, folly::constexpr_strlen(that));
   }
 
+  /**
+   * \overload
+   */
+  constexpr int compare(Range<const Char*> that) const noexcept {
+    return compare(0u, size_, that.begin(), that.size());
+  }
+
   /**
    * Compare two strings for lexicographical ordering.
    * \note Equivalent to
@@ -1618,6 +1622,16 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return compare(this_pos, this_count, that, folly::constexpr_strlen(that));
   }
 
+  /**
+   * \overload
+   */
+  constexpr int compare(
+      std::size_t this_pos,
+      std::size_t this_count,
+      Range<const Char*> that) const noexcept(false) {
+    return compare(this_pos, this_count, that.begin(), that.size());
+  }
+
   /**
    * Compare two strings for lexicographical ordering.
    *
@@ -1648,6 +1662,18 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
         that_count));
   }
 
+  constexpr int compare(
+      std::size_t this_pos,
+      std::size_t this_count,
+      Range<const Char*> that,
+      std::size_t that_count) const noexcept(false) {
+    return compare(
+        this_pos,
+        this_count,
+        that.begin(),
+        detail::fixedstring::checkOverflow(that_count, that.size()));
+  }
+
   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
    * Return a substring from `pos` to the end of the string.
    * \note Equivalent to `BasicFixedString{*this, pos}`
@@ -2660,6 +2686,24 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return b == a;
   }
 
+  /**
+   * \overload
+   */
+  friend constexpr bool operator==(
+      Range<const Char*> a,
+      const BasicFixedString& b) noexcept {
+    return detail::fixedstring::equal_(a.begin(), a.size(), b.data_, b.size_);
+  }
+
+  /**
+   * \overload
+   */
+  friend constexpr bool operator==(
+      const BasicFixedString& a,
+      Range<const Char*> b) noexcept {
+    return b == a;
+  }
+
   friend constexpr bool operator!=(
       const Char* a,
       const BasicFixedString& b) noexcept {
@@ -2675,6 +2719,24 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return !(b == a);
   }
 
+  /**
+   * \overload
+   */
+  friend constexpr bool operator!=(
+      Range<const Char*> a,
+      const BasicFixedString& b) noexcept {
+    return !(a == b);
+  }
+
+  /**
+   * \overload
+   */
+  friend constexpr bool operator!=(
+      const BasicFixedString& a,
+      Range<const Char*> b) noexcept {
+    return !(a == b);
+  }
+
   friend constexpr bool operator<(
       const Char* a,
       const BasicFixedString& b) noexcept {
@@ -2694,6 +2756,28 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
                a.data_, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
   }
 
+  /**
+   * \overload
+   */
+  friend constexpr bool operator<(
+      Range<const Char*> a,
+      const BasicFixedString& b) noexcept {
+    return detail::fixedstring::Cmp::LT ==
+        detail::fixedstring::compare_(
+               a.begin(), 0u, a.size(), b.data_, 0u, b.size_);
+  }
+
+  /**
+   * \overload
+   */
+  friend constexpr bool operator<(
+      const BasicFixedString& a,
+      Range<const Char*> b) noexcept {
+    return detail::fixedstring::Cmp::LT ==
+        detail::fixedstring::compare_(
+               a.data_, 0u, a.size_, b.begin(), 0u, b.size());
+  }
+
   friend constexpr bool operator>(
       const Char* a,
       const BasicFixedString& b) noexcept {
@@ -2709,6 +2793,24 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return b < a;
   }
 
+  /**
+   * \overload
+   */
+  friend constexpr bool operator>(
+      Range<const Char*> a,
+      const BasicFixedString& b) noexcept {
+    return b < a;
+  }
+
+  /**
+   * \overload
+   */
+  friend constexpr bool operator>(
+      const BasicFixedString& a,
+      Range<const Char*> b) noexcept {
+    return b < a;
+  }
+
   friend constexpr bool operator<=(
       const Char* a,
       const BasicFixedString& b) noexcept {
@@ -2724,6 +2826,24 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return !(b < a);
   }
 
+  /**
+   * \overload
+   */
+  friend constexpr bool operator<=(
+      Range<const Char*> const& a,
+      const BasicFixedString& b) noexcept {
+    return !(b < a);
+  }
+
+  /**
+   * \overload
+   */
+  friend constexpr bool operator<=(
+      const BasicFixedString& a,
+      Range<const Char*> b) noexcept {
+    return !(b < a);
+  }
+
   friend constexpr bool operator>=(
       const Char* a,
       const BasicFixedString& b) noexcept {
@@ -2739,6 +2859,24 @@ class BasicFixedString : private detail::fixedstring::FixedStringBase {
     return !(a < b);
   }
 
+  /**
+   * \overload
+   */
+  friend constexpr bool operator>=(
+      Range<const Char*> a,
+      const BasicFixedString& b) noexcept {
+    return !(a < b);
+  }
+
+  /**
+   * \overload
+   */
+  friend constexpr bool operator>=(
+      const BasicFixedString& a,
+      Range<const Char*> const& b) noexcept {
+    return !(a < b);
+  }
+
   /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
    * Asymmetric concatenation
    */
index c0b019bef6f6dacfd5e3a781dd1de9d8b3478aa4..121e94fe4d3070b6e6da052a15e1cfc72e2a02eb 100644 (file)
@@ -312,6 +312,26 @@ TEST(FixedStringCompareTest, Compare) {
   static_assert(tmp3 == "aaa", "");
 }
 
+TEST(FixedStringCompareTest, CompareStdString) {
+  constexpr folly::FixedString<10> tmp1{"aaaaaaaaaa"};
+  std::string const tmp2{"aaaaaaaaaba"};
+  EXPECT_EQ(-1, tmp1.compare(tmp2));
+  // These are specifically testing the operators, and so we can't rely
+  // on whever the implementation details of EXPECT_<OP> might be.
+  EXPECT_FALSE(tmp1 == tmp2);
+  EXPECT_FALSE(tmp2 == tmp1);
+  EXPECT_TRUE(tmp1 != tmp2);
+  EXPECT_TRUE(tmp2 != tmp1);
+  EXPECT_TRUE(tmp1 < tmp2);
+  EXPECT_FALSE(tmp2 < tmp1);
+  EXPECT_TRUE(tmp1 <= tmp2);
+  EXPECT_FALSE(tmp2 <= tmp1);
+  EXPECT_FALSE(tmp1 > tmp2);
+  EXPECT_TRUE(tmp2 > tmp1);
+  EXPECT_FALSE(tmp1 >= tmp2);
+  EXPECT_TRUE(tmp2 >= tmp1);
+}
+
 #if FOLLY_USE_CPP14_CONSTEXPR
 constexpr folly::FixedString<20> constexpr_append_string_test() {
   folly::FixedString<20> a{"hello"}, b{"X world!"};