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,14 +476,24 @@ class Range { ...@@ -476,14 +476,24 @@ class Range {
/// explicit operator conversion to any compatible type /// explicit operator conversion to any compatible type
/// ///
/// A compatible type is one which is constructible with a pair of iterators /// A compatible type is one which is constructible with an iterator and a
/// passed by const-ref. /// size (preferred), or a pair of iterators (fallback), passed by const-ref.
/// ///
/// Participates in overload resolution precisely when the target type is /// Participates in overload resolution precisely when the target type is
/// compatible. This allows std::is_constructible compile-time checks to work. /// compatible. This allows std::is_constructible compile-time checks to work.
template < template <
typename Tgt, typename Tgt,
std::enable_if_t< std::enable_if_t<
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, std::is_constructible<Tgt, Iter const&, Iter const&>::value,
int> = 0> int> = 0>
constexpr explicit operator Tgt() const noexcept( constexpr explicit operator Tgt() const noexcept(
...@@ -493,8 +503,8 @@ class Range { ...@@ -493,8 +503,8 @@ class Range {
/// explicit non-operator conversion to any compatible type /// explicit non-operator conversion to any compatible type
/// ///
/// A compatible type is one which is constructible with a pair of iterators /// A compatible type is one which is constructible with an iterator and a
/// passed by const-ref. /// size (preferred), or a pair of iterators (fallback), passed by const-ref.
/// ///
/// Participates in overload resolution precisely when the target type is /// Participates in overload resolution precisely when the target type is
/// compatible. This allows is_invocable compile-time checks to work. /// compatible. This allows is_invocable compile-time checks to work.
...@@ -506,6 +516,16 @@ class Range { ...@@ -506,6 +516,16 @@ class Range {
/// requires a non-default-constructed allocator. /// requires a non-default-constructed allocator.
template <typename Tgt, typename... Args> template <typename Tgt, typename... Args>
constexpr std::enable_if_t< constexpr std::enable_if_t<
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, std::is_constructible<Tgt, Iter const&, Iter const&>::value,
Tgt> Tgt>
to(Args&&... args) const noexcept( to(Args&&... args) const noexcept(
......
...@@ -1431,6 +1431,23 @@ TEST(Range, LiteralSuffixContainsNulBytes) { ...@@ -1431,6 +1431,23 @@ TEST(Range, LiteralSuffixContainsNulBytes) {
EXPECT_EQ(5u, literalPiece.size()); 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) { TEST(Range, StringPieceExplicitConversionOperator) {
using PieceM = StringPiece; using PieceM = StringPiece;
using PieceC = StringPiece const; using PieceC = StringPiece const;
...@@ -1438,16 +1455,20 @@ TEST(Range, StringPieceExplicitConversionOperator) { ...@@ -1438,16 +1455,20 @@ TEST(Range, StringPieceExplicitConversionOperator) {
EXPECT_FALSE((std::is_convertible<PieceM, int>::value)); EXPECT_FALSE((std::is_convertible<PieceM, int>::value));
EXPECT_FALSE((std::is_convertible<PieceM, std::string>::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, std::vector<char>>::value));
EXPECT_FALSE((std::is_convertible<PieceM, fake_string_view>::value));
EXPECT_FALSE((std::is_constructible<int, PieceM>::value)); EXPECT_FALSE((std::is_constructible<int, PieceM>::value));
EXPECT_TRUE((std::is_constructible<std::string, 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<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, int>::value));
EXPECT_FALSE((std::is_convertible<PieceC, std::string>::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, std::vector<char>>::value));
EXPECT_FALSE((std::is_convertible<PieceC, fake_string_view>::value));
EXPECT_FALSE((std::is_constructible<int, PieceC>::value)); EXPECT_FALSE((std::is_constructible<int, PieceC>::value));
EXPECT_TRUE((std::is_constructible<std::string, 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<std::vector<char>, PieceC>::value));
EXPECT_TRUE((std::is_constructible<fake_string_view, PieceC>::value));
using testing::ElementsAreArray; using testing::ElementsAreArray;
std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}}; std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}};
...@@ -1472,6 +1493,15 @@ TEST(Range, StringPieceExplicitConversionOperator) { ...@@ -1472,6 +1493,15 @@ TEST(Range, StringPieceExplicitConversionOperator) {
EXPECT_THAT(piecec.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(piecem.to<std::vector<char>>(alloc), ElementsAreArray(array));
EXPECT_THAT(piecec.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) { TEST(Range, MutableStringPieceExplicitConversionOperator) {
...@@ -1481,16 +1511,20 @@ TEST(Range, MutableStringPieceExplicitConversionOperator) { ...@@ -1481,16 +1511,20 @@ TEST(Range, MutableStringPieceExplicitConversionOperator) {
EXPECT_FALSE((std::is_convertible<PieceM, int>::value)); EXPECT_FALSE((std::is_convertible<PieceM, int>::value));
EXPECT_FALSE((std::is_convertible<PieceM, std::string>::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, std::vector<char>>::value));
EXPECT_FALSE((std::is_convertible<PieceM, fake_string_view>::value));
EXPECT_FALSE((std::is_constructible<int, PieceM>::value)); EXPECT_FALSE((std::is_constructible<int, PieceM>::value));
EXPECT_TRUE((std::is_constructible<std::string, 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<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, int>::value));
EXPECT_FALSE((std::is_convertible<PieceC, std::string>::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, std::vector<char>>::value));
EXPECT_FALSE((std::is_convertible<PieceC, fake_string_view>::value));
EXPECT_FALSE((std::is_constructible<int, PieceC>::value)); EXPECT_FALSE((std::is_constructible<int, PieceC>::value));
EXPECT_TRUE((std::is_constructible<std::string, 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<std::vector<char>, PieceC>::value));
EXPECT_TRUE((std::is_constructible<fake_string_view, PieceC>::value));
using testing::ElementsAreArray; using testing::ElementsAreArray;
std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}}; std::array<char, 5> array = {{'h', 'e', 'l', 'l', 'o'}};
...@@ -1515,4 +1549,13 @@ TEST(Range, MutableStringPieceExplicitConversionOperator) { ...@@ -1515,4 +1549,13 @@ TEST(Range, MutableStringPieceExplicitConversionOperator) {
EXPECT_THAT(piecec.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(piecem.to<std::vector<char>>(alloc), ElementsAreArray(array));
EXPECT_THAT(piecec.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