Commit 63724d67 authored by Denis Glazachev's avatar Denis Glazachev Committed by Facebook GitHub Bot

Extend resizeWithoutInitialization() to support any std::basic_string<T> (#1339)

Summary:
Currently `folly/memory/UninitializedMemoryHacks.h`'s `resizeWithoutInitialization()` is able to do its job for `std::vector<T>` and `std::string` only. This PR extends it to support `std::basic_string<T>`.

Effectively, replicated the machinery pattern used to achieve the same for any `std::vector<T>`.

Added test cases too, however the test executable is not being built by the `CMakeLists.txt` (had to enable it locally for testing.)

Is there any particular reason why these tests for `folly/memory/UninitializedMemoryHacks.h` are not built/run by default?
`folly/memory/test/UninitializedMemoryHacksODR.cpp`
`folly/memory/test/UninitializedMemoryHacksTest.cpp`
Pull Request resolved: https://github.com/facebook/folly/pull/1339

Reviewed By: Mizuchi

Differential Revision: D20603510

Pulled By: yfeldblum

fbshipit-source-id: dc92ca71cab6a76e2d93c2bbcb4a325bcd70468c
parent a7a1f712
...@@ -33,15 +33,16 @@ struct FollyMemoryDetailTranslationUnitTag {}; ...@@ -33,15 +33,16 @@ struct FollyMemoryDetailTranslationUnitTag {};
} // namespace } // namespace
namespace folly { namespace folly {
namespace detail { namespace detail {
void unsafeStringSetLargerSize(std::string& s, std::size_t n); template <typename T>
void unsafeStringSetLargerSize(std::basic_string<T>& s, std::size_t n);
template <typename T> template <typename T>
void unsafeVectorSetLargerSize(std::vector<T>& v, std::size_t n); void unsafeVectorSetLargerSize(std::vector<T>& v, std::size_t n);
} // namespace detail } // namespace detail
/* /*
* This file provides helper functions resizeWithoutInitialization() * This file provides helper functions resizeWithoutInitialization()
* that can resize std::string or std::vector without constructing or * that can resize std::basic_string or std::vector without constructing
* initializing new elements. * or initializing new elements.
* *
* IMPORTANT: These functions can be unsafe if used improperly. If you * IMPORTANT: These functions can be unsafe if used improperly. If you
* don't write to an element with index >= oldSize and < newSize, reading * don't write to an element with index >= oldSize and < newSize, reading
...@@ -81,9 +82,20 @@ void unsafeVectorSetLargerSize(std::vector<T>& v, std::size_t n); ...@@ -81,9 +82,20 @@ void unsafeVectorSetLargerSize(std::vector<T>& v, std::size_t n);
* any element added to the string by this method unless it has been * any element added to the string by this method unless it has been
* written to by an operation that follows this call. * written to by an operation that follows this call.
* *
* Use the FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(T) macro to
* declare (and inline define) the internals required to call
* resizeWithoutInitialization for a std::basic_string<T>.
* See detailed description of a similar macro for std::vector<T> below.
*
* IMPORTANT: Read the warning at the top of this header file. * IMPORTANT: Read the warning at the top of this header file.
*/ */
inline void resizeWithoutInitialization(std::string& s, std::size_t n) { template <
typename T,
typename =
typename std::enable_if<std::is_trivially_destructible<T>::value>::type>
inline void resizeWithoutInitialization(
std::basic_string<T>& s,
std::size_t n) {
if (n <= s.size()) { if (n <= s.size()) {
s.resize(n); s.resize(n);
} else { } else {
...@@ -135,18 +147,26 @@ void resizeWithoutInitialization(std::vector<T>& v, std::size_t n) { ...@@ -135,18 +147,26 @@ void resizeWithoutInitialization(std::vector<T>& v, std::size_t n) {
namespace detail { namespace detail {
// This machinery bridges template expansion and macro expansion
#define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT_IMPL(TYPE) \
namespace folly { \
namespace detail { \
void unsafeStringSetLargerSizeImpl(std::basic_string<TYPE>& s, std::size_t); \
template <> \
inline void unsafeStringSetLargerSize<TYPE>( \
std::basic_string<TYPE> & s, \
std::size_t n) { \
unsafeStringSetLargerSizeImpl(s, n); \
} \
} \
}
#if defined(_LIBCPP_STRING) #if defined(_LIBCPP_STRING)
// libc++ // libc++
} // namespace detail
} // namespace folly
template void std::string::__set_size(std::size_t);
namespace folly {
namespace detail {
template <typename Tag, typename T, typename A, A Ptr__set_size> template <typename Tag, typename T, typename A, A Ptr__set_size>
struct MakeUnsafeStringSetLargerSize { struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSize( friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s, std::basic_string<T>& s,
std::size_t n) { std::size_t n) {
// s.__set_size(n); // s.__set_size(n);
...@@ -154,46 +174,41 @@ struct MakeUnsafeStringSetLargerSize { ...@@ -154,46 +174,41 @@ struct MakeUnsafeStringSetLargerSize {
(&s[0])[n] = '\0'; (&s[0])[n] = '\0';
} }
}; };
template struct MakeUnsafeStringSetLargerSize<
FollyMemoryDetailTranslationUnitTag, #define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
char, template void std::basic_string<TYPE>::__set_size(std::size_t); \
void (std::string::*)(std::size_t), template struct folly::detail::MakeUnsafeStringSetLargerSize< \
&std::string::__set_size>; FollyMemoryDetailTranslationUnitTag, \
TYPE, \
void (std::basic_string<TYPE>::*)(std::size_t), \
&std::basic_string<TYPE>::__set_size>; \
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT_IMPL(TYPE)
#elif defined(_GLIBCXX_STRING) && _GLIBCXX_USE_CXX11_ABI #elif defined(_GLIBCXX_STRING) && _GLIBCXX_USE_CXX11_ABI
// libstdc++ new implementation with SSO // libstdc++ new implementation with SSO
} // namespace detail
} // namespace folly
template void std::string::_M_set_length(std::size_t);
namespace folly {
namespace detail {
template <typename Tag, typename T, typename A, A Ptr_M_set_length> template <typename Tag, typename T, typename A, A Ptr_M_set_length>
struct MakeUnsafeStringSetLargerSize { struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSize( friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s, std::basic_string<T>& s,
std::size_t n) { std::size_t n) {
// s._M_set_length(n); // s._M_set_length(n);
(s.*Ptr_M_set_length)(n); (s.*Ptr_M_set_length)(n);
} }
}; };
template struct MakeUnsafeStringSetLargerSize<
FollyMemoryDetailTranslationUnitTag, #define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
char, template void std::basic_string<TYPE>::_M_set_length(std::size_t); \
void (std::string::*)(std::size_t), template struct folly::detail::MakeUnsafeStringSetLargerSize< \
&std::string::_M_set_length>; FollyMemoryDetailTranslationUnitTag, \
TYPE, \
void (std::basic_string<TYPE>::*)(std::size_t), \
&std::basic_string<TYPE>::_M_set_length>; \
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT_IMPL(TYPE)
#elif defined(_GLIBCXX_STRING) #elif defined(_GLIBCXX_STRING)
// libstdc++ old implementation // libstdc++ old implementation
} // namespace detail
} // namespace folly
template std::string::_Rep* std::string::_M_rep() const;
template void std::string::_Rep::_M_set_length_and_sharable(std::size_t);
namespace folly {
namespace detail {
template < template <
typename Tag, typename Tag,
typename T, typename T,
...@@ -202,7 +217,7 @@ template < ...@@ -202,7 +217,7 @@ template <
typename B, typename B,
B Ptr_M_set_length_and_sharable> B Ptr_M_set_length_and_sharable>
struct MakeUnsafeStringSetLargerSize { struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSize( friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s, std::basic_string<T>& s,
std::size_t n) { std::size_t n) {
// s._M_rep()->_M_set_length_and_sharable(n); // s._M_rep()->_M_set_length_and_sharable(n);
...@@ -210,25 +225,55 @@ struct MakeUnsafeStringSetLargerSize { ...@@ -210,25 +225,55 @@ struct MakeUnsafeStringSetLargerSize {
(rep->*Ptr_M_set_length_and_sharable)(n); (rep->*Ptr_M_set_length_and_sharable)(n);
} }
}; };
template struct MakeUnsafeStringSetLargerSize<
FollyMemoryDetailTranslationUnitTag, #define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
char, template std::basic_string<TYPE>::_Rep* std::basic_string<TYPE>::_M_rep() \
std::string::_Rep* (std::string::*)() const, const; \
&std::string::_M_rep, template void std::basic_string<TYPE>::_Rep::_M_set_length_and_sharable( \
void (std::string::_Rep::*)(std::size_t), std::size_t); \
&std::string::_Rep::_M_set_length_and_sharable>; template struct folly::detail::MakeUnsafeStringSetLargerSize< \
FollyMemoryDetailTranslationUnitTag, \
TYPE, \
std::basic_string<TYPE>::_Rep* (std::basic_string<TYPE>::*)() const, \
&std::basic_string<TYPE>::_M_rep, \
void (std::basic_string<TYPE>::_Rep::*)(std::size_t), \
&std::basic_string<TYPE>::_Rep::_M_set_length_and_sharable>; \
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT_IMPL(TYPE)
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
// MSVC // MSVC
inline void unsafeStringSetLargerSize(std::string& s, std::size_t n) { template <typename Tag, typename T>
struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s,
std::size_t n) {
s._Eos(n); s._Eos(n);
} }
};
#define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
template struct folly::detail::MakeUnsafeStringSetLargerSize< \
FollyMemoryDetailTranslationUnitTag, \
TYPE>; \
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT_IMPL(TYPE)
#else #else
#warning "No implementation for resizeWithoutInitialization of std::string" #warning \
"No implementation for resizeWithoutInitialization of std::basic_string"
#endif
} // namespace detail
} // namespace folly
#if defined(FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT)
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(char)
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(wchar_t)
#endif #endif
namespace folly {
namespace detail {
// This machinery bridges template expansion and macro expansion // This machinery bridges template expansion and macro expansion
#define FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT_IMPL(TYPE) \ #define FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT_IMPL(TYPE) \
namespace folly { \ namespace folly { \
......
...@@ -17,4 +17,5 @@ ...@@ -17,4 +17,5 @@
#include <folly/memory/UninitializedMemoryHacks.h> #include <folly/memory/UninitializedMemoryHacks.h>
// Verify that this is okay to put in multiple translation units // Verify that this is okay to put in multiple translation units
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(signed char)
FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT(int) FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT(int)
...@@ -282,6 +282,14 @@ TEST(UninitializedMemoryHacks, simpleString) { ...@@ -282,6 +282,14 @@ TEST(UninitializedMemoryHacks, simpleString) {
testSimple<std::string>(); testSimple<std::string>();
} }
TEST(UninitializedMemoryHacks, simpleStringWChar) {
testSimple<std::wstring>();
}
TEST(UninitializedMemoryHacks, simpleStringSChar) {
testSimple<std::basic_string<signed char>>();
}
TEST(UninitializedMemoryHacks, simpleVectorChar) { TEST(UninitializedMemoryHacks, simpleVectorChar) {
testSimple<std::vector<char>>(); testSimple<std::vector<char>>();
} }
...@@ -298,6 +306,14 @@ TEST(UninitializedMemoryHacks, randomString) { ...@@ -298,6 +306,14 @@ TEST(UninitializedMemoryHacks, randomString) {
testRandom<std::string>(); testRandom<std::string>();
} }
TEST(UninitializedMemoryHacks, randomStringWChar) {
testRandom<std::wstring>();
}
TEST(UninitializedMemoryHacks, randomStringSChar) {
testRandom<std::basic_string<signed char>>();
}
TEST(UninitializedMemoryHacks, randomVectorChar) { TEST(UninitializedMemoryHacks, randomVectorChar) {
testRandom<std::vector<char>>(); testRandom<std::vector<char>>();
} }
...@@ -311,4 +327,5 @@ TEST(UninitializedMemoryHacks, randomVectorInt) { ...@@ -311,4 +327,5 @@ TEST(UninitializedMemoryHacks, randomVectorInt) {
} }
// We are deliberately putting this at the bottom to make sure it can follow use // We are deliberately putting this at the bottom to make sure it can follow use
FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(signed char)
FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT(int) FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT(int)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment