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.
This commit is contained in:
Fredrik Roubert 2019-05-03 11:07:27 -07:00 committed by Fredrik Roubert
parent c78d9fa137
commit d8f14e22df
5 changed files with 158 additions and 0 deletions

View 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)

View file

@ -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 :

View 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)

View file

@ -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 @@ 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:

View 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();