ICU-20758 Add a StringPiece constructor for any string view type.
Using the C++ SFINAE (substitution failure is not an error) technique,
it's possible to provide an icu::StringPiece constructor that accepts
any string view type that might be available in the current compilation
unit, without adding any additional dependencies or configuration flags
to ICU.
diff --git a/icu4c/source/common/unicode/stringpiece.h b/icu4c/source/common/unicode/stringpiece.h
index aded0e4..f581091 100644
--- a/icu4c/source/common/unicode/stringpiece.h
+++ b/icu4c/source/common/unicode/stringpiece.h
@@ -31,6 +31,9 @@
#if U_SHOW_CPLUSPLUS_API
+#include <cstddef>
+#include <type_traits>
+
#include "unicode/uobject.h"
#include "unicode/std_string.h"
@@ -77,6 +80,33 @@
*/
StringPiece(const std::string& str)
: ptr_(str.data()), length_(static_cast<int32_t>(str.size())) { }
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Constructs from some other implementation of a string piece class, from any
+ * C++ record type that has these two methods:
+ *
+ * \code{.cpp}
+ *
+ * struct OtherStringPieceClass {
+ * const char* data();
+ * size_t size();
+ * };
+ *
+ * \endcode
+ *
+ * The other string piece class will typically be std::string_view from C++17
+ * or absl::string_view from Abseil.
+ *
+ * @param str the other string piece
+ * @draft ICU 65
+ */
+ template <typename T,
+ typename = typename std::enable_if<
+ std::is_same<decltype(T().data()), const char*>::value &&
+ std::is_same<decltype(T().size()), size_t>::value>::type>
+ StringPiece(T str)
+ : ptr_(str.data()), length_(static_cast<int32_t>(str.size())) {}
+#endif // U_HIDE_DRAFT_API
/**
* Constructs from a const char * pointer and a specified length.
* @param offset a const char * pointer (need not be terminated)
diff --git a/icu4c/source/configure b/icu4c/source/configure
index aac3a44..d1f3e74 100755
--- a/icu4c/source/configure
+++ b/icu4c/source/configure
@@ -2201,6 +2201,60 @@
} # ac_fn_c_check_func
+# ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES
+# ---------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_cxx_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_type
+
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
# Tests whether TYPE exists after having included INCLUDES, setting cache
@@ -7153,6 +7207,29 @@
fi
+# Check if C++17 std::string_view is available.
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+ac_fn_cxx_check_type "$LINENO" "std::string_view" "ac_cv_type_std__string_view" "#include <string_view>
+"
+if test "x$ac_cv_type_std__string_view" = xyes; then :
+
+fi
+
+if test "x$ac_cv_type_std__string_view" = xyes; then :
+ CONFIG_CPPFLAGS="${CONFIG_CPPFLAGS} -DU_HAVE_STRING_VIEW=1"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
# Checks for typedefs
ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default"
if test "x$ac_cv_type_int8_t" = xyes; then :
diff --git a/icu4c/source/configure.ac b/icu4c/source/configure.ac
index 32d7c08..759c495 100644
--- a/icu4c/source/configure.ac
+++ b/icu4c/source/configure.ac
@@ -903,6 +903,14 @@
fi
AC_SUBST(U_HAVE_STRTOD_L)
+# Check if C++17 std::string_view is available.
+AC_LANG_PUSH([C++])
+AC_CHECK_TYPE(std::string_view, [], [], [[#include <string_view>]])
+if test "x$ac_cv_type_std__string_view" = xyes; then :
+ CONFIG_CPPFLAGS="${CONFIG_CPPFLAGS} -DU_HAVE_STRING_VIEW=1"
+fi
+AC_LANG_POP([C++])
+
# Checks for typedefs
AC_CHECK_TYPE(int8_t,signed char)
AC_CHECK_TYPE(uint8_t,unsigned char)
diff --git a/icu4c/source/test/intltest/strtest.cpp b/icu4c/source/test/intltest/strtest.cpp
index b95b525..6381a8b 100644
--- a/icu4c/source/test/intltest/strtest.cpp
+++ b/icu4c/source/test/intltest/strtest.cpp
@@ -14,6 +14,11 @@
* created by: Markus W. Scherer
*/
+#if U_HAVE_STRING_VIEW
+#include <string_view>
+#endif
+
+#include <cstddef>
#include <string.h>
#include "unicode/utypes.h"
@@ -177,6 +182,10 @@
TESTCASE_AUTO(TestSTLCompatibility);
TESTCASE_AUTO(TestStringPiece);
TESTCASE_AUTO(TestStringPieceComparisons);
+ TESTCASE_AUTO(TestStringPieceOther);
+#if U_HAVE_STRING_VIEW
+ TESTCASE_AUTO(TestStringPieceStringView);
+#endif
TESTCASE_AUTO(TestByteSink);
TESTCASE_AUTO(TestCheckedArrayByteSink);
TESTCASE_AUTO(TestStringByteSink);
@@ -346,6 +355,36 @@
}
}
+void
+StringTest::TestStringPieceOther() {
+ static constexpr char msg[] = "Kapow!";
+
+ // Another string piece implementation.
+ struct Other {
+ const char* data() { return msg; }
+ size_t size() { return sizeof msg - 1; }
+ };
+
+ Other other;
+ StringPiece piece(other);
+
+ assertEquals("size()", piece.size(), other.size());
+ assertEquals("data()", piece.data(), other.data());
+}
+
+#if U_HAVE_STRING_VIEW
+void
+StringTest::TestStringPieceStringView() {
+ static constexpr char msg[] = "Kapow!";
+
+ std::string_view view(msg); // C++17
+ StringPiece piece(view);
+
+ assertEquals("size()", piece.size(), view.size());
+ assertEquals("data()", piece.data(), view.data());
+}
+#endif
+
// Verify that ByteSink is subclassable and Flush() overridable.
class SimpleByteSink : public ByteSink {
public:
diff --git a/icu4c/source/test/intltest/strtest.h b/icu4c/source/test/intltest/strtest.h
index 5462afb..4d8a5e7 100644
--- a/icu4c/source/test/intltest/strtest.h
+++ b/icu4c/source/test/intltest/strtest.h
@@ -42,6 +42,10 @@
void Test_UTF8_COUNT_TRAIL_BYTES();
void TestStringPiece();
void TestStringPieceComparisons();
+ void TestStringPieceOther();
+#if U_HAVE_STRING_VIEW
+ void TestStringPieceStringView();
+#endif
void TestByteSink();
void TestCheckedArrayByteSink();
void TestStringByteSink();