]> granicus.if.org Git - icu/commitdiff
ICU-20758 Add a StringPiece constructor for any string view type.
authorFredrik Roubert <roubert@google.com>
Fri, 3 May 2019 18:07:27 +0000 (11:07 -0700)
committerFredrik Roubert <fredrik@roubert.name>
Thu, 15 Aug 2019 11:36:09 +0000 (13:36 +0200)
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.

icu4c/source/common/unicode/stringpiece.h
icu4c/source/configure
icu4c/source/configure.ac
icu4c/source/test/intltest/strtest.cpp
icu4c/source/test/intltest/strtest.h

index aded0e416980d6c95f14c06b8846c0faae796808..f581091f872070c28d44a4d88bb70a105c55cbcd 100644 (file)
@@ -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 @@ class U_COMMON_API StringPiece : public UMemory {
    */
   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)
index aac3a44bdb9eab27c24c3cecd3b7a06edef30e0d..d1f3e74af5fc4b565e246ad16d11c5f2bfd5fdb3 100755 (executable)
@@ -2201,6 +2201,60 @@ $as_echo "$ac_res" >&6; }
 
 } # 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 @@ else
 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 :
index 32d7c08a8d5d957631de3e0526e595bd61818a60..759c4957803e54b4d5dc26153fa6c4431bb91213 100644 (file)
@@ -903,6 +903,14 @@ else
 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)
index b95b525296eafc2005f7d80d01e2b0f69f0e7029..6381a8bf17da08f23115324dbaea57afb7d46ef1 100644 (file)
 *   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 @@ void StringTest::runIndexedTest(int32_t index, UBool exec, const char *&name, ch
     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 @@ StringTest::TestStringPieceComparisons() {
     }
 }
 
+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:
index 5462afb208870167d19657a7cc49d25816f20c63..4d8a5e778a84574573b12ce18e70ac7c6a0aed2d 100644 (file)
@@ -42,6 +42,10 @@ private:
     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();