Add support for getting the current thread's name
[folly.git] / folly / FBString.h
index bb3d339b2f23b85ae9faf2b03b4461107c7475a7..f5b577a777d61cb939ae66e89c9475fe7222fe1e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
 #pragma once
 
 #include <atomic>
+#include <cstddef>
+#include <iosfwd>
 #include <limits>
 #include <type_traits>
 
@@ -135,8 +137,9 @@ inline std::pair<InIt, OutIt> copy_n(
 template <class Pod, class T>
 inline void podFill(Pod* b, Pod* e, T c) {
   FBSTRING_ASSERT(b && e && b <= e);
-  /*static*/ if (sizeof(T) == 1) {
-    memset(b, c, e - b);
+  constexpr auto kUseMemset = sizeof(T) == 1;
+  /* static */ if (kUseMemset) {
+    memset(b, c, size_t(e - b));
   } else {
     auto const ee = b + ((e - b) & ~7u);
     for (; b != ee; b += 8) {
@@ -527,11 +530,14 @@ private:
     std::atomic<size_t> refCount_;
     Char data_[1];
 
+    constexpr static size_t getDataOffset() {
+      return offsetof(RefCounted, data_);
+    }
+
     static RefCounted * fromData(Char * p) {
-      return static_cast<RefCounted*>(
-        static_cast<void*>(
-          static_cast<unsigned char*>(static_cast<void*>(p))
-          - sizeof(refCount_)));
+      return static_cast<RefCounted*>(static_cast<void*>(
+          static_cast<unsigned char*>(static_cast<void*>(p)) -
+          getDataOffset()));
     }
 
     static size_t refs(Char * p) {
@@ -552,14 +558,11 @@ private:
     }
 
     static RefCounted * create(size_t * size) {
-      // Don't forget to allocate one extra Char for the terminating
-      // null. In this case, however, one Char is already part of the
-      // struct.
-      const size_t allocSize = goodMallocSize(
-        sizeof(RefCounted) + *size * sizeof(Char));
+      const size_t allocSize =
+          goodMallocSize(getDataOffset() + (*size + 1) * sizeof(Char));
       auto result = static_cast<RefCounted*>(checkedMalloc(allocSize));
       result->refCount_.store(1, std::memory_order_release);
-      *size = (allocSize - sizeof(RefCounted)) / sizeof(Char);
+      *size = (allocSize - getDataOffset()) / sizeof(Char) - 1;
       return result;
     }
 
@@ -575,19 +578,19 @@ private:
     static RefCounted * reallocate(Char *const data,
                                    const size_t currentSize,
                                    const size_t currentCapacity,
-                                   const size_t newCapacity) {
-      FBSTRING_ASSERT(newCapacity > 0 && newCapacity > currentSize);
+                                   size_t * newCapacity) {
+      FBSTRING_ASSERT(*newCapacity > 0 && *newCapacity > currentSize);
+      const size_t allocNewCapacity =
+          goodMallocSize(getDataOffset() + (*newCapacity + 1) * sizeof(Char));
       auto const dis = fromData(data);
       FBSTRING_ASSERT(dis->refCount_.load(std::memory_order_acquire) == 1);
-      // Don't forget to allocate one extra Char for the terminating
-      // null. In this case, however, one Char is already part of the
-      // struct.
-      auto result = static_cast<RefCounted*>(
-             smartRealloc(dis,
-                          sizeof(RefCounted) + currentSize * sizeof(Char),
-                          sizeof(RefCounted) + currentCapacity * sizeof(Char),
-                          sizeof(RefCounted) + newCapacity * sizeof(Char)));
+      auto result = static_cast<RefCounted*>(smartRealloc(
+          dis,
+          getDataOffset() + (currentSize + 1) * sizeof(Char),
+          getDataOffset() + (currentCapacity + 1) * sizeof(Char),
+          allocNewCapacity));
       FBSTRING_ASSERT(result->refCount_.load(std::memory_order_acquire) == 1);
+      *newCapacity = (allocNewCapacity - getDataOffset()) / sizeof(Char) - 1;
       return result;
     }
   };
@@ -655,7 +658,7 @@ private:
     // small_[maxSmallSize].
     FBSTRING_ASSERT(s <= maxSmallSize);
     constexpr auto shift = kIsLittleEndian ? 0 : 2;
-    small_[maxSmallSize] = (maxSmallSize - s) << shift;
+    small_[maxSmallSize] = char((maxSmallSize - s) << shift);
     small_[s] = '\0';
     FBSTRING_ASSERT(category() == Category::isSmall && size() == s);
   }
@@ -836,7 +839,7 @@ FOLLY_MALLOC_NOINLINE inline void fbstring_core<Char>::reserveLarge(
     if (minCapacity > ml_.capacity()) {
       // Asking for more memory
       auto const newRC = RefCounted::reallocate(
-          ml_.data_, ml_.size_, ml_.capacity(), minCapacity);
+          ml_.data_, ml_.size_, ml_.capacity(), &minCapacity);
       ml_.data_ = newRC->data_;
       ml_.setCapacity(minCapacity, Category::isLarge);
     }
@@ -1184,7 +1187,7 @@ public:
   // Specialization for const char*, const char*
   FOLLY_MALLOC_NOINLINE
   basic_fbstring(const value_type* b, const value_type* e, const A& /*a*/ = A())
-      : store_(b, e - b) {
+      : store_(b, size_type(e - b)) {
   }
 
   // Nonstandard constructor
@@ -1227,7 +1230,24 @@ public:
     return assign(s);
   }
 
-  basic_fbstring& operator=(value_type c);
+  // This actually goes directly against the C++ spec, but the
+  // value_type overload is dangerous, so we're explicitly deleting
+  // any overloads of operator= that could implicitly convert to
+  // value_type.
+  // Note that we do need to explicitly specify the template types because
+  // otherwise MSVC 2017 will aggressively pre-resolve value_type to
+  // traits_type::char_type, which won't compare as equal when determining
+  // which overload the implementation is referring to.
+  // Also note that MSVC 2015 Update 3 requires us to explicitly specify the
+  // namespace in-which to search for basic_fbstring, otherwise it tries to
+  // look for basic_fbstring::basic_fbstring, which is just plain wrong.
+  template <typename TP>
+  typename std::enable_if<
+      std::is_same<
+          typename std::decay<TP>::type,
+          typename folly::basic_fbstring<E, T, A, Storage>::value_type>::value,
+      basic_fbstring<E, T, A, Storage>&>::type
+  operator=(TP c);
 
   basic_fbstring& operator=(std::initializer_list<value_type> il) {
     return assign(il.begin(), il.end());
@@ -1857,8 +1877,13 @@ inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
 }
 
 template <typename E, class T, class A, class S>
-inline basic_fbstring<E, T, A, S>& basic_fbstring<E, T, A, S>::operator=(
-    const value_type c) {
+template <typename TP>
+inline typename std::enable_if<
+    std::is_same<
+        typename std::decay<TP>::type,
+        typename basic_fbstring<E, T, A, S>::value_type>::value,
+    basic_fbstring<E, T, A, S>&>::type
+basic_fbstring<E, T, A, S>::operator=(TP c) {
   Invariant checker(*this);
 
   if (empty()) {
@@ -2640,13 +2665,13 @@ std::basic_istream<
     std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
     typename basic_fbstring<E, T, A, S>::traits_type>& is,
     basic_fbstring<E, T, A, S>& str) {
-  typename std::basic_istream<E, T>::sentry sentry(is);
-  typedef std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type,
-                             typename basic_fbstring<E, T, A, S>::traits_type>
-                        __istream_type;
-  typedef typename __istream_type::ios_base __ios_base;
+  typedef std::basic_istream<
+      typename basic_fbstring<E, T, A, S>::value_type,
+      typename basic_fbstring<E, T, A, S>::traits_type>
+      _istream_type;
+  typename _istream_type::sentry sentry(is);
   size_t extracted = 0;
-  auto err = __ios_base::goodbit;
+  auto err = _istream_type::goodbit;
   if (sentry) {
     auto n = is.width();
     if (n <= 0) {
@@ -2655,7 +2680,7 @@ std::basic_istream<
     str.erase();
     for (auto got = is.rdbuf()->sgetc(); extracted != size_t(n); ++extracted) {
       if (got == T::eof()) {
-        err |= __ios_base::eofbit;
+        err |= _istream_type::eofbit;
         is.width(0);
         break;
       }
@@ -2667,7 +2692,7 @@ std::basic_istream<
     }
   }
   if (!extracted) {
-    err |= __ios_base::failbit;
+    err |= _istream_type::failbit;
   }
   if (err) {
     is.setstate(err);
@@ -2684,28 +2709,31 @@ operator<<(
   typename basic_fbstring<E, T, A, S>::traits_type>& os,
     const basic_fbstring<E, T, A, S>& str) {
 #if _LIBCPP_VERSION
-  typename std::basic_ostream<
-    typename basic_fbstring<E, T, A, S>::value_type,
-    typename basic_fbstring<E, T, A, S>::traits_type>::sentry __s(os);
-  if (__s) {
+  typedef std::basic_ostream<
+      typename basic_fbstring<E, T, A, S>::value_type,
+      typename basic_fbstring<E, T, A, S>::traits_type>
+      _ostream_type;
+  typename _ostream_type::sentry _s(os);
+  if (_s) {
     typedef std::ostreambuf_iterator<
       typename basic_fbstring<E, T, A, S>::value_type,
       typename basic_fbstring<E, T, A, S>::traits_type> _Ip;
     size_t __len = str.size();
     bool __left =
-      (os.flags() & std::ios_base::adjustfield) == std::ios_base::left;
+        (os.flags() & _ostream_type::adjustfield) == _ostream_type::left;
     if (__pad_and_output(_Ip(os),
                          str.data(),
                          __left ? str.data() + __len : str.data(),
                          str.data() + __len,
                          os,
                          os.fill()).failed()) {
-      os.setstate(std::ios_base::badbit | std::ios_base::failbit);
+      os.setstate(_ostream_type::badbit | _ostream_type::failbit);
     }
   }
 #elif defined(_MSC_VER)
+  typedef decltype(os.precision()) streamsize;
   // MSVC doesn't define __ostream_insert
-  os.write(str.data(), str.size());
+  os.write(str.data(), static_cast<streamsize>(str.size()));
 #else
   std::__ostream_insert(os, str.data(), str.size());
 #endif
@@ -2719,34 +2747,90 @@ constexpr typename basic_fbstring<E1, T, A, S>::size_type
 #ifndef _LIBSTDCXX_FBSTRING
 // basic_string compatibility routines
 
-template <typename E, class T, class A, class S>
-inline
-bool operator==(const basic_fbstring<E, T, A, S>& lhs,
-                const std::string& rhs) {
+template <typename E, class T, class A, class S, class A2>
+inline bool operator==(
+    const basic_fbstring<E, T, A, S>& lhs,
+    const std::basic_string<E, T, A2>& rhs) {
   return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0;
 }
 
-template <typename E, class T, class A, class S>
-inline
-bool operator==(const std::string& lhs,
-                const basic_fbstring<E, T, A, S>& rhs) {
+template <typename E, class T, class A, class S, class A2>
+inline bool operator==(
+    const std::basic_string<E, T, A2>& lhs,
+    const basic_fbstring<E, T, A, S>& rhs) {
   return rhs == lhs;
 }
 
-template <typename E, class T, class A, class S>
-inline
-bool operator!=(const basic_fbstring<E, T, A, S>& lhs,
-                const std::string& rhs) {
+template <typename E, class T, class A, class S, class A2>
+inline bool operator!=(
+    const basic_fbstring<E, T, A, S>& lhs,
+    const std::basic_string<E, T, A2>& rhs) {
   return !(lhs == rhs);
 }
 
-template <typename E, class T, class A, class S>
-inline
-bool operator!=(const std::string& lhs,
-                const basic_fbstring<E, T, A, S>& rhs) {
+template <typename E, class T, class A, class S, class A2>
+inline bool operator!=(
+    const std::basic_string<E, T, A2>& lhs,
+    const basic_fbstring<E, T, A, S>& rhs) {
   return !(lhs == rhs);
 }
 
+template <typename E, class T, class A, class S, class A2>
+inline bool operator<(
+    const basic_fbstring<E, T, A, S>& lhs,
+    const std::basic_string<E, T, A2>& rhs) {
+  return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) < 0;
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator>(
+    const basic_fbstring<E, T, A, S>& lhs,
+    const std::basic_string<E, T, A2>& rhs) {
+  return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) > 0;
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator<(
+    const std::basic_string<E, T, A2>& lhs,
+    const basic_fbstring<E, T, A, S>& rhs) {
+  return rhs > lhs;
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator>(
+    const std::basic_string<E, T, A2>& lhs,
+    const basic_fbstring<E, T, A, S>& rhs) {
+  return rhs < lhs;
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator<=(
+    const basic_fbstring<E, T, A, S>& lhs,
+    const std::basic_string<E, T, A2>& rhs) {
+  return !(lhs > rhs);
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator>=(
+    const basic_fbstring<E, T, A, S>& lhs,
+    const std::basic_string<E, T, A2>& rhs) {
+  return !(lhs < rhs);
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator<=(
+    const std::basic_string<E, T, A2>& lhs,
+    const basic_fbstring<E, T, A, S>& rhs) {
+  return !(lhs > rhs);
+}
+
+template <typename E, class T, class A, class S, class A2>
+inline bool operator>=(
+    const std::basic_string<E, T, A2>& lhs,
+    const basic_fbstring<E, T, A, S>& rhs) {
+  return !(lhs < rhs);
+}
+
 #if !defined(_LIBSTDCXX_FBSTRING)
 typedef basic_fbstring<char> fbstring;
 #endif