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 {};
} // namespace
namespace folly {
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>
void unsafeVectorSetLargerSize(std::vector<T>& v, std::size_t n);
} // namespace detail
/*
* This file provides helper functions resizeWithoutInitialization()
* that can resize std::string or std::vector without constructing or
* initializing new elements.
* that can resize std::basic_string or std::vector without constructing
* or initializing new elements.
*
* IMPORTANT: These functions can be unsafe if used improperly. If you
* 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);
* any element added to the string by this method unless it has been
* 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.
*/
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()) {
s.resize(n);
} else {
......@@ -135,18 +147,26 @@ void resizeWithoutInitialization(std::vector<T>& v, std::size_t n) {
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)
// 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>
struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSize(
friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s,
std::size_t n) {
// s.__set_size(n);
......@@ -154,46 +174,41 @@ struct MakeUnsafeStringSetLargerSize {
(&s[0])[n] = '\0';
}
};
template struct MakeUnsafeStringSetLargerSize<
FollyMemoryDetailTranslationUnitTag,
char,
void (std::string::*)(std::size_t),
&std::string::__set_size>;
#define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
template void std::basic_string<TYPE>::__set_size(std::size_t); \
template struct folly::detail::MakeUnsafeStringSetLargerSize< \
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
// 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>
struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSize(
friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s,
std::size_t n) {
// s._M_set_length(n);
(s.*Ptr_M_set_length)(n);
}
};
template struct MakeUnsafeStringSetLargerSize<
FollyMemoryDetailTranslationUnitTag,
char,
void (std::string::*)(std::size_t),
&std::string::_M_set_length>;
#define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
template void std::basic_string<TYPE>::_M_set_length(std::size_t); \
template struct folly::detail::MakeUnsafeStringSetLargerSize< \
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)
// 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 <
typename Tag,
typename T,
......@@ -202,7 +217,7 @@ template <
typename B,
B Ptr_M_set_length_and_sharable>
struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSize(
friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s,
std::size_t n) {
// s._M_rep()->_M_set_length_and_sharable(n);
......@@ -210,25 +225,55 @@ struct MakeUnsafeStringSetLargerSize {
(rep->*Ptr_M_set_length_and_sharable)(n);
}
};
template struct MakeUnsafeStringSetLargerSize<
FollyMemoryDetailTranslationUnitTag,
char,
std::string::_Rep* (std::string::*)() const,
&std::string::_M_rep,
void (std::string::_Rep::*)(std::size_t),
&std::string::_Rep::_M_set_length_and_sharable>;
#define FOLLY_DECLARE_STRING_RESIZE_WITHOUT_INIT(TYPE) \
template std::basic_string<TYPE>::_Rep* std::basic_string<TYPE>::_M_rep() \
const; \
template void std::basic_string<TYPE>::_Rep::_M_set_length_and_sharable( \
std::size_t); \
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)
// MSVC
inline void unsafeStringSetLargerSize(std::string& s, std::size_t n) {
s._Eos(n);
}
template <typename Tag, typename T>
struct MakeUnsafeStringSetLargerSize {
friend void unsafeStringSetLargerSizeImpl(
std::basic_string<T>& s,
std::size_t 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
#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
namespace folly {
namespace detail {
// This machinery bridges template expansion and macro expansion
#define FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT_IMPL(TYPE) \
namespace folly { \
......
......@@ -17,4 +17,5 @@
#include <folly/memory/UninitializedMemoryHacks.h>
// 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)
......@@ -282,6 +282,14 @@ TEST(UninitializedMemoryHacks, simpleString) {
testSimple<std::string>();
}
TEST(UninitializedMemoryHacks, simpleStringWChar) {
testSimple<std::wstring>();
}
TEST(UninitializedMemoryHacks, simpleStringSChar) {
testSimple<std::basic_string<signed char>>();
}
TEST(UninitializedMemoryHacks, simpleVectorChar) {
testSimple<std::vector<char>>();
}
......@@ -298,6 +306,14 @@ TEST(UninitializedMemoryHacks, randomString) {
testRandom<std::string>();
}
TEST(UninitializedMemoryHacks, randomStringWChar) {
testRandom<std::wstring>();
}
TEST(UninitializedMemoryHacks, randomStringSChar) {
testRandom<std::basic_string<signed char>>();
}
TEST(UninitializedMemoryHacks, randomVectorChar) {
testRandom<std::vector<char>>();
}
......@@ -311,4 +327,5 @@ TEST(UninitializedMemoryHacks, randomVectorInt) {
}
// 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)
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