Disabling conversion with contained value for Optional
[folly.git] / folly / FBString.h
index 7da9a3068a8d349155f03f5187b05d65282454af..ea15414858e68b5deb0f8f66539c06cc0e824981 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2013 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <cassert>
 
 #include "folly/Traits.h"
-#include "folly/Likely.h"
 #include "folly/Malloc.h"
 #include "folly/Hash.h"
 
 #endif
 
+// We defined these here rather than including Likely.h to avoid
+// redefinition errors when fbstring is imported into libstdc++.
+#define FBSTRING_LIKELY(x)   (__builtin_expect((x), 1))
+#define FBSTRING_UNLIKELY(x) (__builtin_expect((x), 0))
+
 #include <atomic>
 #include <limits>
 #include <type_traits>
@@ -244,8 +248,10 @@ private:
  * gcc-4.7 throws what appears to be some false positive uninitialized
  * warnings for the members of the MediumLarge struct.  So, mute them here.
  */
+#if defined(__GNUC__) && !defined(__clang__)
 # pragma GCC diagnostic push
 # pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
 
 /**
  * This is the core of the string. The code should work on 32- and
@@ -274,7 +280,7 @@ public:
   fbstring_core() {
     // Only initialize the tag, will set the MSBs (i.e. the small
     // string size) to zero too
-    ml_.capacity_ = maxSmallSize << (8 * (sizeof(size_t) - 1));
+    ml_.capacity_ = maxSmallSize << (8 * (sizeof(size_t) - sizeof(Char)));
     // or: setSmallSize(0);
     writeTerminator();
     assert(category() == isSmall && size() == 0);
@@ -641,7 +647,7 @@ public:
 
   void push_back(Char c) {
     assert(capacity() >= size());
-    size_t sz, cp;
+    size_t sz;
     if (category() == isSmall) {
       sz = smallSize();
       if (sz < maxSmallSize) {
@@ -653,14 +659,16 @@ public:
       reserve(maxSmallSize * 2);
     } else {
       sz = ml_.size_;
-      cp = capacity();  // != ml_.capacity() for isShared()
-      if (sz == cp) reserve(cp * 3 / 2);
+      if (sz == capacity()) {  // always true for isShared()
+        reserve(sz * 3 / 2);  // ensures not shared
+      }
     }
+    assert(!isShared());
     assert(capacity() >= sz + 1);
     // Category can't be small - we took care of that above
     assert(category() == isMedium || category() == isLarge);
     ml_.size_ = sz + 1;
-    mutable_data()[sz] = c;
+    ml_.data_[sz] = c;
     writeTerminator();
   }
 
@@ -727,7 +735,7 @@ private:
       return static_cast<RefCounted*>(
         static_cast<void*>(
           static_cast<unsigned char*>(static_cast<void*>(p))
-          - offsetof(RefCounted, data_)));
+          - sizeof(refCount_)));
     }
 
     static size_t refs(Char * p) {
@@ -828,7 +836,9 @@ private:
   }
 };
 
+#if defined(__GNUC__) && !defined(__clang__)
 # pragma GCC diagnostic pop
+#endif
 
 #ifndef _LIBSTDCXX_FBSTRING
 /**
@@ -1036,8 +1046,8 @@ public:
   ~basic_fbstring() {
   }
 
-  basic_fbstring& operator=(const basic_fbstring & lhs) {
-    if (&lhs == this) {
+  basic_fbstring& operator=(const basic_fbstring& lhs) {
+    if (FBSTRING_UNLIKELY(&lhs == this)) {
       return *this;
     }
     auto const oldSize = size();
@@ -1060,6 +1070,11 @@ public:
 
   // Move assignment
   basic_fbstring& operator=(basic_fbstring&& goner) {
+    if (FBSTRING_UNLIKELY(&goner == this)) {
+      // Compatibility with std::basic_string<>,
+      // 21.4.2 [string.cons] / 23 requires self-move-assignment support.
+      return *this;
+    }
     // No need of this anymore
     this->~basic_fbstring();
     // Move the goner into this
@@ -1257,7 +1272,7 @@ public:
     Invariant checker(*this);
     (void) checker;
 #endif
-    if (UNLIKELY(!n)) {
+    if (FBSTRING_UNLIKELY(!n)) {
       // Unlikely but must be done
       return *this;
     }
@@ -1269,8 +1284,8 @@ public:
     // std::less_equal, which is guaranteed to offer a total order
     // over pointers. See discussion at http://goo.gl/Cy2ya for more
     // info.
-    static const std::less_equal<const value_type*> le;
-    if (UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
+    std::less_equal<const value_type*> le;
+    if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
       assert(le(s + n, oldData + oldSize));
       const size_type offset = s - oldData;
       store_.reserve(oldSize + n);
@@ -2041,7 +2056,7 @@ template <typename E, class T, class A, class S>
 inline
 bool operator==(const basic_fbstring<E, T, A, S>& lhs,
                 const basic_fbstring<E, T, A, S>& rhs) {
-  return lhs.compare(rhs) == 0; }
+  return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; }
 
 template <typename E, class T, class A, class S>
 inline
@@ -2321,4 +2336,7 @@ struct hash< ::folly::fbstring> {
 
 #endif // _LIBSTDCXX_FBSTRING
 
+#undef FBSTRING_LIKELY
+#undef FBSTRING_UNLIKELY
+
 #endif // FOLLY_BASE_FBSTRING_H_