Commit 24d559b8 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Range explicit conversion to any

Summary:
[Folly] `Range` explicit conversion to any target type, with overloads enabled only for target types which are explicitly constructible from two iterators.

Also changes `Range::to` to do similar, but permits additional arguments to be forwarded as trailing arguments to the target type constructor.

For example, this makes `std::string`, `folly::fbstring`, `std::vector<char>`, and all variants with default-constructible custom allocators, to be constructible from (but not convertible from) `folly::StringPiece`.

Reviewed By: nbronson

Differential Revision: D8386240

fbshipit-source-id: 2426191d1c8ac71cd5832f784e83bbe09b8716e7
parent 074433f1
......@@ -474,11 +474,48 @@ class Range {
return detail::value_before(e_);
}
template <typename Tgt>
auto to() const
-> decltype(Tgt(std::declval<Iter const&>(), std::declval<size_type>())) {
return Tgt(b_, size());
template <
typename Tgt,
std::enable_if_t<std::is_constructible<Tgt, Iter&, Iter&>::value, int> =
0>
FOLLY_CPP14_CONSTEXPR explicit operator Tgt() noexcept(
noexcept(Tgt(std::declval<Iter&>(), std::declval<Iter&>()))) {
return Tgt(b_, e_);
}
template <
typename Tgt,
std::enable_if_t<
std::is_constructible<Tgt, Iter const&, Iter const&>::value,
int> = 0>
constexpr explicit operator Tgt() const noexcept(
noexcept(Tgt(std::declval<Iter const&>(), std::declval<Iter const&>()))) {
return Tgt(b_, e_);
}
template <typename Tgt, typename... Args>
FOLLY_CPP14_CONSTEXPR auto to(Args&&... args) noexcept(noexcept(
Tgt(std::declval<Iter&>(),
std::declval<Iter&>(),
static_cast<Args&&>(args)...)))
-> decltype(
Tgt(std::declval<Iter&>(),
std::declval<Iter&>(),
static_cast<Args&&>(args)...)) {
return Tgt(b_, e_, static_cast<Args&&>(args)...);
}
template <typename Tgt, typename... Args>
constexpr auto to(Args&&... args) const noexcept(noexcept(
Tgt(std::declval<Iter const&>(),
std::declval<Iter const&>(),
static_cast<Args&&>(args)...)))
-> decltype(
Tgt(std::declval<Iter const&>(),
std::declval<Iter const&>(),
static_cast<Args&&>(args)...)) {
return Tgt(b_, e_, static_cast<Args&&>(args)...);
}
// Works only for Range<const char*> and Range<char*>
std::string str() const {
return to<std::string>();
......
......@@ -1430,3 +1430,89 @@ TEST(Range, LiteralSuffixContainsNulBytes) {
constexpr auto literalPiece = "\0foo\0"_sp;
EXPECT_EQ(5u, literalPiece.size());
}
TEST(Range, StringPieceExplicitConversionOperator) {
using PieceM = StringPiece;
using PieceC = StringPiece const;
EXPECT_FALSE((std::is_convertible<PieceM, int>::value));
EXPECT_FALSE((std::is_convertible<PieceM, std::string>::value));
EXPECT_FALSE((std::is_convertible<PieceM, std::vector<char>>::value));
EXPECT_FALSE((std::is_constructible<int, PieceM>::value));
EXPECT_TRUE((std::is_constructible<std::string, PieceM>::value));
EXPECT_TRUE((std::is_constructible<std::vector<char>, PieceM>::value));
EXPECT_FALSE((std::is_convertible<PieceC, int>::value));
EXPECT_FALSE((std::is_convertible<PieceC, std::string>::value));
EXPECT_FALSE((std::is_convertible<PieceC, std::vector<char>>::value));
EXPECT_FALSE((std::is_constructible<int, PieceC>::value));
EXPECT_TRUE((std::is_constructible<std::string, PieceC>::value));
EXPECT_TRUE((std::is_constructible<std::vector<char>, PieceC>::value));
using testing::ElementsAreArray;
std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}};
PieceM piecem{array};
PieceC piecec{array};
std::allocator<char> alloc;
EXPECT_EQ("hello", std::string(piecem));
EXPECT_EQ("hello", std::string(piecec));
EXPECT_EQ("hello", std::string{piecem});
EXPECT_EQ("hello", std::string{piecec});
EXPECT_EQ("hello", piecem.to<std::string>());
EXPECT_EQ("hello", piecec.to<std::string>());
EXPECT_EQ("hello", piecem.to<std::string>(alloc));
EXPECT_EQ("hello", piecec.to<std::string>(alloc));
EXPECT_THAT(std::vector<char>(piecem), ElementsAreArray(array));
EXPECT_THAT(std::vector<char>(piecec), ElementsAreArray(array));
EXPECT_THAT(std::vector<char>{piecem}, ElementsAreArray(array));
EXPECT_THAT(std::vector<char>{piecec}, ElementsAreArray(array));
EXPECT_THAT(piecem.to<std::vector<char>>(), ElementsAreArray(array));
EXPECT_THAT(piecec.to<std::vector<char>>(), ElementsAreArray(array));
EXPECT_THAT(piecem.to<std::vector<char>>(alloc), ElementsAreArray(array));
EXPECT_THAT(piecec.to<std::vector<char>>(alloc), ElementsAreArray(array));
}
TEST(Range, MutableStringPieceExplicitConversionOperator) {
using PieceM = MutableStringPiece;
using PieceC = MutableStringPiece const;
EXPECT_FALSE((std::is_convertible<PieceM, int>::value));
EXPECT_FALSE((std::is_convertible<PieceM, std::string>::value));
EXPECT_FALSE((std::is_convertible<PieceM, std::vector<char>>::value));
EXPECT_FALSE((std::is_constructible<int, PieceM>::value));
EXPECT_TRUE((std::is_constructible<std::string, PieceM>::value));
EXPECT_TRUE((std::is_constructible<std::vector<char>, PieceM>::value));
EXPECT_FALSE((std::is_convertible<PieceC, int>::value));
EXPECT_FALSE((std::is_convertible<PieceC, std::string>::value));
EXPECT_FALSE((std::is_convertible<PieceC, std::vector<char>>::value));
EXPECT_FALSE((std::is_constructible<int, PieceC>::value));
EXPECT_TRUE((std::is_constructible<std::string, PieceC>::value));
EXPECT_TRUE((std::is_constructible<std::vector<char>, PieceC>::value));
using testing::ElementsAreArray;
std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}};
PieceM piecem{array};
PieceC piecec{array};
std::allocator<char> alloc;
EXPECT_EQ("hello", std::string(piecem));
EXPECT_EQ("hello", std::string(piecec));
EXPECT_EQ("hello", std::string{piecem});
EXPECT_EQ("hello", std::string{piecec});
EXPECT_EQ("hello", piecem.to<std::string>());
EXPECT_EQ("hello", piecec.to<std::string>());
EXPECT_EQ("hello", piecem.to<std::string>(alloc));
EXPECT_EQ("hello", piecec.to<std::string>(alloc));
EXPECT_THAT(std::vector<char>(piecem), ElementsAreArray(array));
EXPECT_THAT(std::vector<char>(piecec), ElementsAreArray(array));
EXPECT_THAT(std::vector<char>{piecem}, ElementsAreArray(array));
EXPECT_THAT(std::vector<char>{piecec}, ElementsAreArray(array));
EXPECT_THAT(piecem.to<std::vector<char>>(), ElementsAreArray(array));
EXPECT_THAT(piecec.to<std::vector<char>>(), ElementsAreArray(array));
EXPECT_THAT(piecem.to<std::vector<char>>(alloc), ElementsAreArray(array));
EXPECT_THAT(piecec.to<std::vector<char>>(alloc), ElementsAreArray(array));
}
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