X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FFBString.h;h=5db1e61e19329bc2fc86c82d90d2bb0ff18036e4;hb=5d24ef4474ee6177d8f3e8a8dc24035fded6f65c;hp=bb3d339b2f23b85ae9faf2b03b4461107c7475a7;hpb=fc838f2b6a5f850b9465dd9aa448bb1039d11d8a;p=folly.git diff --git a/folly/FBString.h b/folly/FBString.h index bb3d339b..5db1e61e 100644 --- a/folly/FBString.h +++ b/folly/FBString.h @@ -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 +#include +#include #include #include @@ -54,13 +56,7 @@ #include #include #include - -#if FOLLY_HAVE_DEPRECATED_ASSOC -#ifdef _GLIBCXX_SYMVER -#include -#include -#endif -#endif +#include // When used in folly, assertions are not disabled. #define FBSTRING_ASSERT(expr) assert(expr) @@ -77,13 +73,13 @@ #define FBSTRING_UNLIKELY(x) (x) #endif -#pragma GCC diagnostic push +FOLLY_PUSH_WARNING // Ignore shadowing warnings within this file, so includers can use -Wshadow. -#pragma GCC diagnostic ignored "-Wshadow" +FOLLY_GCC_DISABLE_WARNING("-Wshadow") // GCC 4.9 has a false positive in setSmallSize (probably // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124), disable // compile-time array bound checking. -#pragma GCC diagnostic ignored "-Warray-bounds" +FOLLY_GCC_DISABLE_WARNING("-Warray-bounds") // FBString cannot use throw when replacing std::string, though it may still // use std::__throw_* @@ -135,8 +131,9 @@ inline std::pair copy_n( template 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 +524,14 @@ private: std::atomic refCount_; Char data_[1]; + constexpr static size_t getDataOffset() { + return offsetof(RefCounted, data_); + } + static RefCounted * fromData(Char * p) { - return static_cast( - static_cast( - static_cast(static_cast(p)) - - sizeof(refCount_))); + return static_cast(static_cast( + static_cast(static_cast(p)) - + getDataOffset())); } static size_t refs(Char * p) { @@ -552,14 +552,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(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 +572,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( - smartRealloc(dis, - sizeof(RefCounted) + currentSize * sizeof(Char), - sizeof(RefCounted) + currentCapacity * sizeof(Char), - sizeof(RefCounted) + newCapacity * sizeof(Char))); + auto result = static_cast(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 +652,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 +833,7 @@ FOLLY_MALLOC_NOINLINE inline void fbstring_core::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); } @@ -1144,9 +1141,9 @@ public: #ifndef _LIBSTDCXX_FBSTRING // This is defined for compatibility with std::string - /* implicit */ basic_fbstring(const std::string& str) - : store_(str.data(), str.size()) { - } + template + /* implicit */ basic_fbstring(const std::basic_string& str) + : store_(str.data(), str.size()) {} #endif basic_fbstring(const basic_fbstring& str, @@ -1184,7 +1181,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 @@ -1208,13 +1205,14 @@ public: #ifndef _LIBSTDCXX_FBSTRING // Compatibility with std::string - basic_fbstring & operator=(const std::string & rhs) { + template + basic_fbstring& operator=(const std::basic_string& rhs) { return assign(rhs.data(), rhs.size()); } // Compatibility with std::string - std::string toStdString() const { - return std::string(data(), size()); + std::basic_string toStdString() const { + return std::basic_string(data(), size()); } #else // A lot of code in fbcode still uses this method, so keep it here for now. @@ -1227,7 +1225,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 std::enable_if< + std::is_same< + typename std::decay::type, + typename folly::basic_fbstring::value_type>::value, + basic_fbstring&>::type + operator=(TP c); basic_fbstring& operator=(std::initializer_list il) { return assign(il.begin(), il.end()); @@ -1857,8 +1872,13 @@ inline basic_fbstring& basic_fbstring::operator=( } template -inline basic_fbstring& basic_fbstring::operator=( - const value_type c) { +template +inline typename std::enable_if< + std::is_same< + typename std::decay::type, + typename basic_fbstring::value_type>::value, + basic_fbstring&>::type +basic_fbstring::operator=(TP c) { Invariant checker(*this); if (empty()) { @@ -2640,13 +2660,13 @@ std::basic_istream< std::basic_istream::value_type, typename basic_fbstring::traits_type>& is, basic_fbstring& str) { - typename std::basic_istream::sentry sentry(is); - typedef std::basic_istream::value_type, - typename basic_fbstring::traits_type> - __istream_type; - typedef typename __istream_type::ios_base __ios_base; + typedef std::basic_istream< + typename basic_fbstring::value_type, + typename basic_fbstring::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 +2675,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 +2687,7 @@ std::basic_istream< } } if (!extracted) { - err |= __ios_base::failbit; + err |= _istream_type::failbit; } if (err) { is.setstate(err); @@ -2684,28 +2704,31 @@ operator<<( typename basic_fbstring::traits_type>& os, const basic_fbstring& str) { #if _LIBCPP_VERSION - typename std::basic_ostream< - typename basic_fbstring::value_type, - typename basic_fbstring::traits_type>::sentry __s(os); - if (__s) { + typedef std::basic_ostream< + typename basic_fbstring::value_type, + typename basic_fbstring::traits_type> + _ostream_type; + typename _ostream_type::sentry _s(os); + if (_s) { typedef std::ostreambuf_iterator< typename basic_fbstring::value_type, typename basic_fbstring::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(str.size())); #else std::__ostream_insert(os, str.data(), str.size()); #endif @@ -2719,34 +2742,90 @@ constexpr typename basic_fbstring::size_type #ifndef _LIBSTDCXX_FBSTRING // basic_string compatibility routines -template -inline -bool operator==(const basic_fbstring& lhs, - const std::string& rhs) { +template +inline bool operator==( + const basic_fbstring& lhs, + const std::basic_string& rhs) { return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0; } -template -inline -bool operator==(const std::string& lhs, - const basic_fbstring& rhs) { +template +inline bool operator==( + const std::basic_string& lhs, + const basic_fbstring& rhs) { return rhs == lhs; } -template -inline -bool operator!=(const basic_fbstring& lhs, - const std::string& rhs) { +template +inline bool operator!=( + const basic_fbstring& lhs, + const std::basic_string& rhs) { return !(lhs == rhs); } -template -inline -bool operator!=(const std::string& lhs, - const basic_fbstring& rhs) { +template +inline bool operator!=( + const std::basic_string& lhs, + const basic_fbstring& rhs) { return !(lhs == rhs); } +template +inline bool operator<( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) < 0; +} + +template +inline bool operator>( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) > 0; +} + +template +inline bool operator<( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return rhs > lhs; +} + +template +inline bool operator>( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return rhs < lhs; +} + +template +inline bool operator<=( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return !(lhs > rhs); +} + +template +inline bool operator>=( + const basic_fbstring& lhs, + const std::basic_string& rhs) { + return !(lhs < rhs); +} + +template +inline bool operator<=( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return !(lhs > rhs); +} + +template +inline bool operator>=( + const std::basic_string& lhs, + const basic_fbstring& rhs) { + return !(lhs < rhs); +} + #if !defined(_LIBSTDCXX_FBSTRING) typedef basic_fbstring fbstring; #endif @@ -2789,22 +2868,12 @@ FOLLY_FBSTRING_HASH } // namespace std -#if FOLLY_HAVE_DEPRECATED_ASSOC -#if defined(_GLIBCXX_SYMVER) && !defined(__BIONIC__) -namespace __gnu_cxx { - -FOLLY_FBSTRING_HASH - -} // namespace __gnu_cxx -#endif // _GLIBCXX_SYMVER && !__BIONIC__ -#endif // FOLLY_HAVE_DEPRECATED_ASSOC - #undef FOLLY_FBSTRING_HASH #undef FOLLY_FBSTRING_HASH1 #endif // _LIBSTDCXX_FBSTRING -#pragma GCC diagnostic pop +FOLLY_POP_WARNING #undef FBSTRING_DISABLE_SSO #undef FBSTRING_SANITIZE_ADDRESS