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

Generic conversion from Range in cases like std::string_view

Summary: [Folly] Generic conversion from `Range` in cases like `std::string_view` which are constructible with `Iter, size_type` instead of `Iter, Iter`.

Reviewed By: vitaut

Differential Revision: D8907212

fbshipit-source-id: 6f93581b7185d4d10925aa57175f130dff2576e3
parent 667f7df0
......@@ -476,15 +476,25 @@ class Range {
/// explicit operator conversion to any compatible type
///
/// A compatible type is one which is constructible with a pair of iterators
/// passed by const-ref.
/// A compatible type is one which is constructible with an iterator and a
/// size (preferred), or a pair of iterators (fallback), passed by const-ref.
///
/// Participates in overload resolution precisely when the target type is
/// compatible. This allows std::is_constructible compile-time checks to work.
template <
typename Tgt,
std::enable_if_t<
std::is_constructible<Tgt, Iter const&, Iter const&>::value,
std::is_constructible<Tgt, Iter const&, size_type>::value,
int> = 0>
constexpr explicit operator Tgt() const noexcept(
std::is_nothrow_constructible<Tgt, Iter const&, size_type>::value) {
return Tgt(b_, walk_size());
}
template <
typename Tgt,
std::enable_if_t<
!std::is_constructible<Tgt, Iter const&, size_type>::value &&
std::is_constructible<Tgt, Iter const&, Iter const&>::value,
int> = 0>
constexpr explicit operator Tgt() const noexcept(
std::is_nothrow_constructible<Tgt, Iter const&, Iter const&>::value) {
......@@ -493,8 +503,8 @@ class Range {
/// explicit non-operator conversion to any compatible type
///
/// A compatible type is one which is constructible with a pair of iterators
/// passed by const-ref.
/// A compatible type is one which is constructible with an iterator and a
/// size (preferred), or a pair of iterators (fallback), passed by const-ref.
///
/// Participates in overload resolution precisely when the target type is
/// compatible. This allows is_invocable compile-time checks to work.
......@@ -506,7 +516,17 @@ class Range {
/// requires a non-default-constructed allocator.
template <typename Tgt, typename... Args>
constexpr std::enable_if_t<
std::is_constructible<Tgt, Iter const&, Iter const&>::value,
std::is_constructible<Tgt, Iter const&, size_type>::value,
Tgt>
to(Args&&... args) const noexcept(
std::is_nothrow_constructible<Tgt, Iter const&, size_type, Args&&...>::
value) {
return Tgt(b_, walk_size(), static_cast<Args&&>(args)...);
}
template <typename Tgt, typename... Args>
constexpr std::enable_if_t<
!std::is_constructible<Tgt, Iter const&, size_type>::value &&
std::is_constructible<Tgt, Iter const&, Iter const&>::value,
Tgt>
to(Args&&... args) const noexcept(
std::is_nothrow_constructible<Tgt, Iter const&, Iter const&, Args&&...>::
......
......@@ -1431,6 +1431,23 @@ TEST(Range, LiteralSuffixContainsNulBytes) {
EXPECT_EQ(5u, literalPiece.size());
}
class tag {};
class fake_string_view {
private:
StringPiece piece_;
public:
using size_type = std::size_t;
explicit fake_string_view(char const* s, size_type c, tag = {})
: piece_(s, c) {}
/* implicit */ operator StringPiece() const {
return piece_;
}
friend bool operator==(char const* rhs, fake_string_view lhs) {
return rhs == lhs.piece_;
}
};
TEST(Range, StringPieceExplicitConversionOperator) {
using PieceM = StringPiece;
using PieceC = StringPiece const;
......@@ -1438,16 +1455,20 @@ TEST(Range, StringPieceExplicitConversionOperator) {
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_convertible<PieceM, fake_string_view>::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_TRUE((std::is_constructible<fake_string_view, 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_convertible<PieceC, fake_string_view>::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));
EXPECT_TRUE((std::is_constructible<fake_string_view, PieceC>::value));
using testing::ElementsAreArray;
std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}};
......@@ -1472,6 +1493,15 @@ TEST(Range, StringPieceExplicitConversionOperator) {
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));
EXPECT_EQ("hello", fake_string_view(piecem));
EXPECT_EQ("hello", fake_string_view(piecec));
EXPECT_EQ("hello", fake_string_view{piecem});
EXPECT_EQ("hello", fake_string_view{piecec});
EXPECT_EQ("hello", piecem.to<fake_string_view>());
EXPECT_EQ("hello", piecec.to<fake_string_view>());
EXPECT_EQ("hello", piecem.to<fake_string_view>(tag{}));
EXPECT_EQ("hello", piecec.to<fake_string_view>(tag{}));
}
TEST(Range, MutableStringPieceExplicitConversionOperator) {
......@@ -1481,16 +1511,20 @@ TEST(Range, MutableStringPieceExplicitConversionOperator) {
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_convertible<PieceM, fake_string_view>::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_TRUE((std::is_constructible<fake_string_view, 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_convertible<PieceC, fake_string_view>::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));
EXPECT_TRUE((std::is_constructible<fake_string_view, PieceC>::value));
using testing::ElementsAreArray;
std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}};
......@@ -1515,4 +1549,13 @@ TEST(Range, MutableStringPieceExplicitConversionOperator) {
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));
EXPECT_EQ("hello", fake_string_view(piecem));
EXPECT_EQ("hello", fake_string_view(piecec));
EXPECT_EQ("hello", fake_string_view{piecem});
EXPECT_EQ("hello", fake_string_view{piecec});
EXPECT_EQ("hello", piecem.to<fake_string_view>());
EXPECT_EQ("hello", piecec.to<fake_string_view>());
EXPECT_EQ("hello", piecem.to<fake_string_view>(tag{}));
EXPECT_EQ("hello", piecec.to<fake_string_view>(tag{}));
}
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