summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2022-10-12 16:23:33 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2022-10-13 07:18:41 +0200
commitaf2879e434fa0dc6b2a626617ed865e4f66eb5ad (patch)
treebb25da5b207884ab9fd8d1c49d8dee18b9f1ad12
parentb3869749719288e6d1951030f07dc3fbccc0c222 (diff)
Deduplicate stringconcat more
In the process, drop ToStringHelper::allowO(U)StringConcat, because we can deduce this information from ToStringHelper's addData itself. To do that, addData was converted to ToStringHelper::operator(), which allows to use std::is_invocable_v on the helper class. Change-Id: Ic77878ca0ff65ada8c0a942191bc11de15b9ad2a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141254 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r--compilerplugins/clang/stringadd.cxx1
-rw-r--r--compilerplugins/clang/stringconcatauto.cxx8
-rw-r--r--compilerplugins/clang/stringview.cxx7
-rw-r--r--compilerplugins/clang/test/stringconcatauto.cxx12
-rw-r--r--compilerplugins/clang/test/stringview.cxx4
-rw-r--r--include/rtl/strbuf.hxx19
-rw-r--r--include/rtl/string.hxx34
-rw-r--r--include/rtl/stringconcat.hxx396
-rw-r--r--include/rtl/ustrbuf.hxx17
-rw-r--r--include/rtl/ustring.hxx38
10 files changed, 210 insertions, 326 deletions
diff --git a/compilerplugins/clang/stringadd.cxx b/compilerplugins/clang/stringadd.cxx
index 339192a78687..9254e9190ed5 100644
--- a/compilerplugins/clang/stringadd.cxx
+++ b/compilerplugins/clang/stringadd.cxx
@@ -233,6 +233,7 @@ bool StringAdd::VisitCXXOperatorCallExpr(CXXOperatorCallExpr const* operatorCall
auto tc = loplugin::TypeCheck(operatorCall->getType()->getUnqualifiedDesugaredType());
if (!tc.Struct("OUStringConcat").Namespace("rtl").GlobalNamespace()
&& !tc.Struct("OStringConcat").Namespace("rtl").GlobalNamespace()
+ && !tc.Struct("StringConcat").Namespace("rtl").GlobalNamespace()
&& !tc.Class("OUString").Namespace("rtl").GlobalNamespace()
&& !tc.Class("OString").Namespace("rtl").GlobalNamespace())
return true;
diff --git a/compilerplugins/clang/stringconcatauto.cxx b/compilerplugins/clang/stringconcatauto.cxx
index 561aedec8070..02517a4db0ba 100644
--- a/compilerplugins/clang/stringconcatauto.cxx
+++ b/compilerplugins/clang/stringconcatauto.cxx
@@ -83,10 +83,10 @@ bool StringConcatAuto::checkDecl( const DeclaratorDecl* decl, QualType type, con
return true;
auto const tc = loplugin::TypeCheck( type.getNonReferenceType().getCanonicalType());
const char* typeString = nullptr;
- if( tc.Struct("OUStringConcat").Namespace("rtl").GlobalNamespace())
- typeString = "OUString";
- else if( tc.Struct("OStringConcat").Namespace("rtl").GlobalNamespace())
- typeString = "OString";
+ if( tc.Struct("StringConcat").Namespace("rtl").GlobalNamespace())
+ typeString = "O(U)String";
+ else if( tc.Struct("StringNumber").Namespace("rtl").GlobalNamespace())
+ typeString = "O(U)String";
else if( tc.Struct("OUStringNumber").Namespace("rtl").GlobalNamespace())
typeString = "OUString";
else if( tc.Struct("OStringNumber").Namespace("rtl").GlobalNamespace())
diff --git a/compilerplugins/clang/stringview.cxx b/compilerplugins/clang/stringview.cxx
index c1606908dbc7..16e53b1c12e9 100644
--- a/compilerplugins/clang/stringview.cxx
+++ b/compilerplugins/clang/stringview.cxx
@@ -206,6 +206,10 @@ void StringView::handleCXXConstructExpr(CXXConstructExpr const* expr)
.Class("OUStringLiteral")
.Namespace("rtl")
.GlobalNamespace()
+ || tc.RvalueReference()
+ .Struct("StringNumberBase")
+ .Namespace("rtl")
+ .GlobalNamespace()
|| tc.RvalueReference().Struct("OStringNumber").Namespace("rtl").GlobalNamespace()
|| tc.RvalueReference().Struct("OUStringNumber").Namespace("rtl").GlobalNamespace()
|| tc.ClassOrStruct("basic_string_view").StdNamespace())
@@ -214,7 +218,8 @@ void StringView::handleCXXConstructExpr(CXXConstructExpr const* expr)
break;
}
if (tc.RvalueReference().Struct("OStringConcat").Namespace("rtl").GlobalNamespace()
- || tc.RvalueReference().Struct("OUStringConcat").Namespace("rtl").GlobalNamespace())
+ || tc.RvalueReference().Struct("OUStringConcat").Namespace("rtl").GlobalNamespace()
+ || tc.RvalueReference().Struct("StringConcat").Namespace("rtl").GlobalNamespace())
{
argType = expr->getArg(0)->IgnoreImplicit()->getType();
extra = ViaConcatenation;
diff --git a/compilerplugins/clang/test/stringconcatauto.cxx b/compilerplugins/clang/test/stringconcatauto.cxx
index dc450503d25e..72044f80b150 100644
--- a/compilerplugins/clang/test/stringconcatauto.cxx
+++ b/compilerplugins/clang/test/stringconcatauto.cxx
@@ -15,14 +15,14 @@ void foo()
{
auto str1 = "str1" + OUString::number(10);
// expected-error-re@-1 {{creating a variable of type {{.+}} will make it reference temporaries}}
- // expected-note@-2 {{use OUString instead}}
+ // expected-note@-2 {{use O(U)String instead}}
OUString str2 = "str2" + OUString::number(20) + "ing";
const auto& str3 = "str3" + OUString::number(30);
// expected-error-re@-1 {{creating a variable of type {{.+}} will make it reference temporaries}}
- // expected-note@-2 {{use OUString instead}}
+ // expected-note@-2 {{use O(U)String instead}}
const auto str4 = "str4" + OString::number(40);
// expected-error-re@-1 {{creating a variable of type {{.+}} will make it reference temporaries}}
- // expected-note@-2 {{use OString instead}}
+ // expected-note@-2 {{use O(U)String instead}}
auto str5 = OUString::number(50);
// expected-error-re@-1 {{creating a variable of type '{{(rtl::)?}}OUStringNumber<{{.*}}>' will make it reference temporaries}}
// expected-note@-2 {{use OUString instead}}
@@ -37,7 +37,7 @@ struct A
{
auto bar()
// expected-error-re@-1 {{returning a variable of type {{.+}} will make it reference temporaries}}
- // expected-note@-2 {{use OString instead}}
+ // expected-note@-2 {{use O(U)String instead}}
{
return "bar" + OString::number(110);
}
@@ -53,8 +53,8 @@ template <typename T> void fun(const T& par)
// parameters are without warnings
{
const T& var = par;
- // expected-error-re@-1 {{creating a variable of type 'const rtl::OUStringConcat<{{.*}}> &' will make it reference temporaries}}
- // expected-note@-2 {{use OUString instead}}
+ // expected-error-re@-1 {{creating a variable of type 'const rtl::StringConcat<{{.*}}> &' will make it reference temporaries}}
+ // expected-note@-2 {{use O(U)String instead}}
(void)var;
}
diff --git a/compilerplugins/clang/test/stringview.cxx b/compilerplugins/clang/test/stringview.cxx
index f578a5f50e8d..cd59f6c3c73a 100644
--- a/compilerplugins/clang/test/stringview.cxx
+++ b/compilerplugins/clang/test/stringview.cxx
@@ -167,7 +167,7 @@ void f5(char const* s1, sal_Int32 n1, char16_t const* s2, sal_Int32 n2, OString
call_view(OString(std::string_view("foo")));
// expected-error-re@+1 {{instead of an '{{(rtl::)?}}OString' constructed from a 'OStringNumber<int>', pass a 'std::string_view' [loplugin:stringview]}}
call_view(OString(OString::number(0)));
- // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OString' constructed from a 'typename std::enable_if_t<ToStringHelper<OString>::allowOStringConcat && ToStringHelper<OString>::allowOStringConcat, OStringConcat<OString, OString>{{ ?}}>' (aka 'rtl::OStringConcat<rtl::OString, rtl::OString>'), pass a 'std::string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
+ // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OString' constructed from a 'OStringConcat<rtl::OString, rtl::OString>' (aka 'StringConcat<char, rtl::OString, rtl::OString>'), pass a 'std::string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
call_view(OString(s3 + s3));
// expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString', pass a 'std::u16string_view' [loplugin:stringview]}}
call_view(OUString());
@@ -192,7 +192,7 @@ void f5(char const* s1, sal_Int32 n1, char16_t const* s2, sal_Int32 n2, OString
call_view(OUString(std::u16string_view(u"foo")));
// expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString' constructed from a 'OUStringNumber<int>', pass a 'std::u16string_view' [loplugin:stringview]}}
call_view(OUString(OUString::number(0)));
- // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString' constructed from a 'typename std::enable_if_t<ToStringHelper<OUString>::allowOUStringConcat && ToStringHelper<OUString>::allowOUStringConcat, OUStringConcat<OUString, OUString>{{ ?}}>' (aka 'rtl::OUStringConcat<rtl::OUString, rtl::OUString>'), pass a 'std::u16string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
+ // expected-error-re@+1 {{instead of an '{{(rtl::)?}}OUString' constructed from a 'OUStringConcat<rtl::OUString, rtl::OUString>' (aka 'StringConcat<char16_t, rtl::OUString, rtl::OUString>'), pass a 'std::u16string_view' via 'rtl::Concat2View' [loplugin:stringview]}}
call_view(OUString(s4 + s4));
(void)(s3 == l1);
diff --git a/include/rtl/strbuf.hxx b/include/rtl/strbuf.hxx
index 5917c1812e9c..dbdcd7fea39a 100644
--- a/include/rtl/strbuf.hxx
+++ b/include/rtl/strbuf.hxx
@@ -246,9 +246,9 @@ public:
@overload
@internal
*/
- template< typename T >
- OStringBuffer( OStringNumber< T >&& n )
- : OStringBuffer( OString( n ))
+ template< typename T, std::size_t N >
+ OStringBuffer( StringNumberBase< char, T, N >&& n )
+ : OStringBuffer( n.buf, n.length)
{}
#endif
@@ -334,8 +334,8 @@ public:
}
/** @overload @internal */
- template<typename T>
- OStringBuffer & operator =(OStringNumber<T> && n)
+ template<typename T, std::size_t N>
+ OStringBuffer & operator =(StringNumberBase<char, T, N> && n)
{
*this = OStringBuffer( std::move ( n ));
return *this;
@@ -618,8 +618,8 @@ public:
@overload
@internal
*/
- template< typename T >
- OStringBuffer& append( OStringNumber< T >&& c )
+ template< typename T, std::size_t N >
+ OStringBuffer& append( StringNumberBase< char, T, N >&& c )
{
return append( c.buf, c.length );
}
@@ -1106,11 +1106,8 @@ private:
template<> struct ToStringHelper<OStringBuffer> {
static std::size_t length(OStringBuffer const & s) { return s.getLength(); }
- static char * addData(char * buffer, OStringBuffer const & s) SAL_RETURNS_NONNULL
+ char * operator()(char * buffer, OStringBuffer const & s) const SAL_RETURNS_NONNULL
{ return addDataHelper(buffer, s.getStr(), s.getLength()); }
-
- static constexpr bool allowOStringConcat = true;
- static constexpr bool allowOUStringConcat = false;
};
#endif
diff --git a/include/rtl/string.hxx b/include/rtl/string.hxx
index 0e0c3c75d5a9..3d9ef8ff9aa3 100644
--- a/include/rtl/string.hxx
+++ b/include/rtl/string.hxx
@@ -394,8 +394,8 @@ public:
@overload
@internal
*/
- template< typename T >
- OString( OStringNumber< T >&& n )
+ template< typename T, std::size_t N >
+ OString( StringNumberBase< char, T, N >&& n )
: OString( n.buf, n.length )
{}
#endif
@@ -548,12 +548,12 @@ public:
@overload
@internal
*/
- template< typename T >
- OString& operator+=( OStringNumber< T >&& n ) & {
+ template< typename T, std::size_t N >
+ OString& operator+=( StringNumberBase< char, T, N >&& n ) & {
return operator +=(std::string_view(n.buf, n.length));
}
- template<typename T> void operator +=(
- OStringNumber<T> &&) && = delete;
+ template<typename T, std::size_t N> void operator +=(
+ StringNumberBase<char, T, N> &&) && = delete;
#endif
/**
@@ -2154,16 +2154,14 @@ public:
//
// would not compile):
template<typename T> [[nodiscard]] static
- typename std::enable_if_t<
- ToStringHelper<T>::allowOStringConcat, OStringConcat<OStringConcatMarker, T>>
+ OStringConcat<OStringConcatMarker, T>
Concat(T const & value) { return OStringConcat<OStringConcatMarker, T>({}, value); }
// This overload is needed so that an argument of type 'char const[N]' ends up as
// 'OStringConcat<rtl::OStringConcatMarker, char const[N]>' rather than as
// 'OStringConcat<rtl::OStringConcatMarker, char[N]>':
template<typename T, std::size_t N> [[nodiscard]] static
- typename std::enable_if_t<
- ToStringHelper<T[N]>::allowOStringConcat, OStringConcat<OStringConcatMarker, T[N]>>
+ OStringConcat<OStringConcatMarker, T[N]>
Concat(T (& value)[N]) { return OStringConcat<OStringConcatMarker, T[N]>({}, value); }
#endif
};
@@ -2188,24 +2186,20 @@ inline bool operator !=(StringConcatenation<char> const & lhs, OString const & r
*/
template<>
struct ToStringHelper< OString >
- {
+{
static std::size_t length( const OString& s ) { return s.getLength(); }
- static char* addData( char* buffer, const OString& s ) { return addDataHelper( buffer, s.getStr(), s.getLength()); }
- static const bool allowOStringConcat = true;
- static const bool allowOUStringConcat = false;
- };
+ char* operator()( char* buffer, const OString& s ) const { return addDataHelper( buffer, s.getStr(), s.getLength()); }
+};
/**
@internal
*/
template<std::size_t N>
struct ToStringHelper< OStringLiteral<N> >
- {
+{
static constexpr std::size_t length( const OStringLiteral<N>& str ) { return str.getLength(); }
- static char* addData( char* buffer, const OStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
- static const bool allowOStringConcat = true;
- static const bool allowOUStringConcat = false;
- };
+ char* operator()( char* buffer, const OStringLiteral<N>& str ) const { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
+};
/**
@internal
diff --git a/include/rtl/stringconcat.hxx b/include/rtl/stringconcat.hxx
index c2862c5c49ad..24dabe15c0bb 100644
--- a/include/rtl/stringconcat.hxx
+++ b/include/rtl/stringconcat.hxx
@@ -60,283 +60,220 @@ Helper class for converting a given type to a string representation.
*/
template< typename T >
struct ToStringHelper
- {
+{
/// Return length of the string representation of the given object.
- static std::size_t length( const T& );
+ // static std::size_t length( const T& );
/// Add 8-bit representation of the given object to the given buffer and return position right after the added data.
- static char* addData( char* buffer, const T& ) SAL_RETURNS_NONNULL;
+ // char* operator()( char* buffer, const T& ) const SAL_RETURNS_NONNULL;
/// Add Unicode representation of the given object to the given buffer and return position right after the added data.
- static sal_Unicode* addData( sal_Unicode* buffer, const T& ) SAL_RETURNS_NONNULL;
- /// If true, T can be used in concatenation resulting in OString.
- static const bool allowOStringConcat = false;
- /// If true, T can be used in concatenation resulting in OUString.
- static const bool allowOUStringConcat = false;
- };
+ // sal_Unicode* operator()( sal_Unicode* buffer, const T& ) const SAL_RETURNS_NONNULL;
+};
-inline
-char* addDataHelper( char* buffer, const char* data, std::size_t length )
- {
- if (length != 0) {
- memcpy( buffer, data, length );
- }
- return buffer + length;
- }
+/// If true, T can be used in concatenation resulting in O(U)String.
+template<typename C, typename T, class Enable = void> constexpr bool allowStringConcat = false;
+template<typename C, typename T> constexpr bool allowStringConcat<C, T, std::enable_if_t<std::is_invocable_v<ToStringHelper<T>, C*, T>>> = true;
-inline
-sal_Unicode* addDataHelper( sal_Unicode* buffer, const sal_Unicode* data, std::size_t length )
- {
+template <typename C> inline
+C* addDataHelper( C* buffer, const C* data, std::size_t length )
+{
if (length != 0) {
- memcpy( buffer, data, length * sizeof( sal_Unicode ));
+ memcpy( buffer, data, length * sizeof( C ));
}
return buffer + length;
- }
+}
inline
sal_Unicode* addDataLiteral( sal_Unicode* buffer, const char* data, std::size_t length )
- {
+{
for( std::size_t i = 0; i != length; ++i )
*buffer++ = *data++;
return buffer;
- }
-
-inline
-char* addDataCString( char* buffer, const char* str )
- {
- while( *str != '\0' )
- *buffer++ = *str++;
- return buffer;
- }
+}
-inline
-sal_Unicode* addDataUString( sal_Unicode* buffer, const sal_Unicode* str )
- {
+template <typename C> inline
+C* addDataString( C* buffer, const C* str )
+{
while( *str != '\0' )
*buffer++ = *str++;
return buffer;
- }
+}
template<>
struct ToStringHelper< const char* >
- {
+{
static std::size_t length( const char* str ) {
return str ? strlen( str ) : 0;
}
- static char* addData( char* buffer, const char* str ) {
- return str ? addDataCString( buffer, str ) : buffer;
+ char* operator()( char* buffer, const char* str ) const {
+ return str ? addDataString( buffer, str ) : buffer;
}
- static const bool allowOStringConcat = true;
- static const bool allowOUStringConcat = false;
- };
+};
template<>
struct ToStringHelper< char* > : public ToStringHelper< const char* > {};
template< std::size_t N >
struct ToStringHelper< char[ N ] >
- {
+{
static std::size_t length( const char str[ N ] ) {
return strlen( str );
}
- static char* addData( char* buffer, const char str[ N ] ) { return addDataCString( buffer, str ); }
- static const bool allowOStringConcat = true;
- static const bool allowOUStringConcat = false;
- };
+ char* operator()( char* buffer, const char str[ N ] ) const { return addDataString( buffer, str ); }
+};
template< std::size_t N >
struct ToStringHelper< const char[ N ] >
- {
+{
static std::size_t length( const char str[ N ] ) { (void)str; assert( strlen( str ) == N - 1 ); return N - 1; }
- static char* addData( char* buffer, const char str[ N ] ) { return addDataHelper( buffer, str, N - 1 ); }
- static sal_Unicode* addData( sal_Unicode* buffer, const char str[ N ] ) { return addDataLiteral( buffer, str, N - 1 ); }
- static const bool allowOStringConcat = true;
- static const bool allowOUStringConcat = true;
- };
+ char* operator()( char* buffer, const char str[ N ] ) const { return addDataHelper( buffer, str, N - 1 ); }
+ sal_Unicode* operator()( sal_Unicode* buffer, const char str[ N ] ) const { return addDataLiteral( buffer, str, N - 1 ); }
+};
template<>
struct ToStringHelper<OStringChar>
- {
+{
static std::size_t length(OStringChar) { return 1; }
- static char* addData(char* buffer, OStringChar data)
+ char* operator()(char* buffer, OStringChar data) const
{ return addDataHelper(buffer, &data.c, 1); }
- static bool const allowOStringConcat = true;
- static bool const allowOUStringConcat = false;
- };
+};
template<>
struct ToStringHelper< const sal_Unicode* >
- {
+{
static std::size_t length( const sal_Unicode* str ) {
return str ? std::char_traits<char16_t>::length( str ) : 0;
}
- static sal_Unicode* addData( sal_Unicode* buffer, const sal_Unicode* str ) {
- return str ? addDataUString( buffer, str ) : buffer;
+ sal_Unicode* operator()( sal_Unicode* buffer, const sal_Unicode* str ) const {
+ return str ? addDataString( buffer, str ) : buffer;
}
- static const bool allowOStringConcat = false;
- static const bool allowOUStringConcat = true;
- };
+};
template<>
struct ToStringHelper< sal_Unicode* > : public ToStringHelper< const sal_Unicode* > {};
template<std::size_t N>
struct ToStringHelper<sal_Unicode[ N ]>
- {
+{
static std::size_t length( const sal_Unicode str[ N ] ) {
return std::char_traits<char16_t>::length( str );
}
- static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
+ sal_Unicode * operator()(sal_Unicode * buffer, sal_Unicode const str[N]) const
{ return addDataHelper(buffer, str, N - 1); }
- static bool const allowOStringConcat = false;
- static bool const allowOUStringConcat = true;
- };
+};
template<std::size_t N>
struct ToStringHelper<sal_Unicode const[N]>
- {
+{
static std::size_t length( const sal_Unicode str[ N ] ) { (void)str; assert( std::char_traits<char16_t>::length( str ) == N - 1 ); return N - 1; }
- static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
+ sal_Unicode * operator()(sal_Unicode * buffer, sal_Unicode const str[N]) const
{ return addDataHelper(buffer, str, N - 1); }
- static bool const allowOStringConcat = false;
- static bool const allowOUStringConcat = true;
- };
+};
template<>
struct ToStringHelper<OUStringChar_>
- {
+{
static std::size_t length(OUStringChar_) { return 1; }
- static sal_Unicode * addData(sal_Unicode * buffer, OUStringChar_ literal)
+ sal_Unicode * operator()(sal_Unicode * buffer, OUStringChar_ literal) const
{ return addDataHelper(buffer, &literal.c, 1); }
- static bool const allowOStringConcat = false;
- static bool const allowOUStringConcat = true;
- };
-
-/**
-@internal
-
-Objects returned by operator+, instead of OString. These objects (possibly recursively) keep a representation of the whole
-concatenation operation.
-
-If you get a build error related to this class, you most probably need to explicitly convert the result of a string
-concatenation to OString.
-*/
-template< typename T1, typename T2 >
-struct OStringConcat
- {
- public:
- OStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
- std::size_t length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
- char* addData( char* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
- // NOTE here could be functions that would forward to the "real" temporary OString. Note however that e.g. getStr()
- // is not so simple, as the OString temporary must live long enough (i.e. can't be created here in a function, a wrapper
- // temporary object containing it must be returned instead).
- private:
- const T1& left;
- const T2& right;
- };
+};
/**
@internal
-Objects returned by operator+, instead of OUString. These objects (possibly recursively) keep a representation of the whole
+Objects returned by operator+, instead of O(U)String. These objects (possibly recursively) keep a representation of the whole
concatenation operation.
If you get a build error related to this class, you most probably need to explicitly convert the result of a string
-concatenation to OUString.
+concatenation to O(U)String.
*/
-template< typename T1, typename T2 >
-struct OUStringConcat
- {
- public:
- OUStringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
- std::size_t length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
- sal_Unicode* addData( sal_Unicode* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >::addData( ToStringHelper< T1 >::addData( buffer, left ), right ); }
- private:
- const T1& left;
- const T2& right;
- };
+template <typename C, typename T1, typename T2, std::enable_if_t<allowStringConcat<C, T1> && allowStringConcat<C, T2>, int> = 0 >
+struct StringConcat
+{
+public:
+ StringConcat( const T1& left_, const T2& right_ ) : left( left_ ), right( right_ ) {}
+ std::size_t length() const { return ToStringHelper< T1 >::length( left ) + ToStringHelper< T2 >::length( right ); }
+ C* addData( C* buffer ) const SAL_RETURNS_NONNULL { return ToStringHelper< T2 >()( ToStringHelper< T1 >()( buffer, left ), right ); }
+ // NOTE here could be functions that would forward to the "real" temporary O(U)String. Note however that e.g. getStr()
+ // is not so simple, as the O(U)String temporary must live long enough (i.e. can't be created here in a function, a wrapper
+ // temporary object containing it must be returned instead).
+private:
+ const T1& left;
+ const T2& right;
+};
-template< typename T1, typename T2 >
-struct ToStringHelper< OStringConcat< T1, T2 > >
- {
- static std::size_t length( const OStringConcat< T1, T2 >& c ) { return c.length(); }
- static char* addData( char* buffer, const OStringConcat< T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
- static const bool allowOStringConcat = ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat;
- static const bool allowOUStringConcat = false;
- };
+template <typename C, typename T1, typename T2> struct ToStringHelper<StringConcat<C, T1, T2>>
+{
+ static std::size_t length(const StringConcat<C, T1, T2 >& c) { return c.length(); }
+ C* operator()(C* buffer, const StringConcat<C, T1, T2>& c) const SAL_RETURNS_NONNULL { return c.addData(buffer); }
+};
-template< typename T1, typename T2 >
-struct ToStringHelper< OUStringConcat< T1, T2 > >
- {
- static std::size_t length( const OUStringConcat< T1, T2 >& c ) { return c.length(); }
- static sal_Unicode* addData( sal_Unicode* buffer, const OUStringConcat< T1, T2 >& c ) SAL_RETURNS_NONNULL { return c.addData( buffer ); }
- static const bool allowOStringConcat = false;
- static const bool allowOUStringConcat = ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat;
- };
+template <typename T1, typename T2> using OStringConcat = StringConcat<char, T1, T2>;
+template <typename T1, typename T2> using OUStringConcat = StringConcat<sal_Unicode, T1, T2>;
template< typename T1, typename T2 >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOStringConcat && ToStringHelper< T2 >::allowOStringConcat, OStringConcat< T1, T2 > > operator+( const T1& left, const T2& right )
- {
+OStringConcat< T1, T2 > operator+( const T1& left, const T2& right )
+{
return OStringConcat< T1, T2 >( left, right );
- }
+}
// char[N] and const char[N] need to be done explicitly, otherwise the compiler likes to treat them the same way for some reason
template< typename T, std::size_t N >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< T, const char[ N ] > > operator+( const T& left, const char (&right)[ N ] )
- {
+OStringConcat< T, const char[ N ] > operator+( const T& left, const char (&right)[ N ] )
+{
return OStringConcat< T, const char[ N ] >( left, right );
- }
+}
template< typename T, std::size_t N >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< const char[ N ], T > > operator+( const char (&left)[ N ], const T& right )
- {
+OStringConcat< const char[ N ], T > operator+( const char (&left)[ N ], const T& right )
+{
return OStringConcat< const char[ N ], T >( left, right );
- }
+}
template< typename T, std::size_t N >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< T, char[ N ] > > operator+( const T& left, char (&right)[ N ] )
- {
+OStringConcat< T, char[ N ] > operator+( const T& left, char (&right)[ N ] )
+{
return OStringConcat< T, char[ N ] >( left, right );
- }
+}
template< typename T, std::size_t N >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T >::allowOStringConcat, OStringConcat< char[ N ], T > > operator+( char (&left)[ N ], const T& right )
- {
+OStringConcat< char[ N ], T > operator+( char (&left)[ N ], const T& right )
+{
return OStringConcat< char[ N ], T >( left, right );
- }
+}
template< typename T1, typename T2 >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat, OUStringConcat< T1, T2 > > operator+( const T1& left, const T2& right )
- {
+OUStringConcat< T1, T2 > operator+( const T1& left, const T2& right )
+{
return OUStringConcat< T1, T2 >( left, right );
- }
+}
template< typename T1, typename T2 >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && libreoffice_internal::ConstCharArrayDetector< T1, void >::ok, OUStringConcat< T1, T2 > > operator+( T1& left, const T2& right )
- {
+typename std::enable_if_t< libreoffice_internal::ConstCharArrayDetector< T1, void >::ok, OUStringConcat< T1, T2 > > operator+( T1& left, const T2& right )
+{
return OUStringConcat< T1, T2 >( left, right );
- }
+}
template< typename T1, typename T2 >
[[nodiscard]]
inline
-typename std::enable_if_t< ToStringHelper< T1 >::allowOUStringConcat && ToStringHelper< T2 >::allowOUStringConcat && libreoffice_internal::ConstCharArrayDetector< T2, void >::ok, OUStringConcat< T1, T2 > > operator+( const T1& left, T2& right )
- {
+typename std::enable_if_t< libreoffice_internal::ConstCharArrayDetector< T2, void >::ok, OUStringConcat< T1, T2 > > operator+( const T1& left, T2& right )
+{
return OUStringConcat< T1, T2 >( left, right );
- }
+}
#ifdef RTL_STRING_UNITTEST_CONCAT
// Special overload to catch the remaining invalid combinations. The helper struct must
@@ -386,6 +323,31 @@ template <typename T1, typename T2> auto Concat2View(OUStringConcat<T1, T2> cons
}
/**
+* O(U)StringNumber implementation
+*/
+
+template <typename C, typename Number, std::size_t nBufSize> struct StringNumberBase
+{
+ using number_t = Number;
+ using base_t = StringNumberBase;
+ // O(U)String::number(value).getStr() is very common (writing xml code, ...),
+ // so implement that one also here, to avoid having to explicitly convert
+ // to O(U)String in all such places
+ const C* getStr() const SAL_RETURNS_NONNULL { return buf; }
+ StringNumberBase&& toAsciiUpperCase()
+ {
+ if constexpr (sizeof(C) == sizeof(char))
+ rtl_str_toAsciiUpperCase_WithLength(buf, length);
+ else
+ rtl_ustr_toAsciiUpperCase_WithLength(buf, length);
+ return std::move(*this);
+ }
+ operator std::basic_string_view<C>() const { return std::basic_string_view<C>(buf, length); }
+ C buf[nBufSize];
+ sal_Int32 length;
+};
+
+/**
@internal
Objects returned by OString::number(), instead of OString. These objects keep a representation of the number() operation.
@@ -396,68 +358,41 @@ OString::number() to OString.
template< typename T >
struct OStringNumber;
-template <typename Number, std::size_t nBufSize> struct OStringNumberBase
-{
- using number_t = Number;
- // OString::number(value).getStr() is very common (writing xml code, ...),
- // so implement that one also here, to avoid having to explicitly to convert
- // to OString in all such places
- const char * getStr() const SAL_RETURNS_NONNULL { return buf; }
- OStringNumber<number_t>&& toAsciiUpperCase()
- {
- rtl_str_toAsciiUpperCase_WithLength(buf, length);
- return std::move(*static_cast<OStringNumber<number_t>*>(this));
- }
- operator std::string_view() const { return std::string_view(buf, length); }
- char buf[nBufSize];
- sal_Int32 length;
-};
-
template<>
struct OStringNumber< int >
- : public OStringNumberBase<int, RTL_STR_MAX_VALUEOFINT32>
+ : public StringNumberBase<char, int, RTL_STR_MAX_VALUEOFINT32>
{
OStringNumber(number_t i, sal_Int16 radix) { length = rtl_str_valueOfInt32(buf, i, radix); }
};
template<>
struct OStringNumber< long long >
- : public OStringNumberBase<long long, RTL_STR_MAX_VALUEOFINT64>
+ : public StringNumberBase<char, long long, RTL_STR_MAX_VALUEOFINT64>
{
OStringNumber(number_t i, sal_Int16 radix) { length = rtl_str_valueOfInt64(buf, i, radix); }
};
template<>
struct OStringNumber< unsigned long long >
- : public OStringNumberBase<unsigned long long, RTL_STR_MAX_VALUEOFUINT64>
+ : public StringNumberBase<char, unsigned long long, RTL_STR_MAX_VALUEOFUINT64>
{
OStringNumber(number_t i, sal_Int16 radix) { length = rtl_str_valueOfUInt64(buf, i, radix); }
};
template<>
struct OStringNumber< float >
- : public OStringNumberBase<float, RTL_STR_MAX_VALUEOFFLOAT>
+ : public StringNumberBase<char, float, RTL_STR_MAX_VALUEOFFLOAT>
{
OStringNumber(number_t f) { length = rtl_str_valueOfFloat(buf, f); }
};
template<>
struct OStringNumber< double >
- : public OStringNumberBase<double, RTL_STR_MAX_VALUEOFDOUBLE>
+ : public StringNumberBase<char, double, RTL_STR_MAX_VALUEOFDOUBLE>
{
OStringNumber(number_t d) { length = rtl_str_valueOfDouble(buf, d); }
};
-template< typename T >
-struct ToStringHelper< OStringNumber< T > >
- {
- static std::size_t length( const OStringNumber< T >& n ) { return n.length; }
- static char* addData( char* buffer, const OStringNumber< T >& n ) SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
- static const bool allowOStringConcat = true;
- static const bool allowOUStringConcat = false;
- };
-
-
/**
@internal
@@ -469,109 +404,70 @@ OUString::number() to OUString.
template< typename T >
struct OUStringNumber;
-template <typename Number, std::size_t nBufSize> struct OUStringNumberBase
-{
- using number_t = Number;
- OUStringNumber<number_t>&& toAsciiUpperCase()
- {
- rtl_ustr_toAsciiUpperCase_WithLength(buf, length);
- return std::move(*static_cast<OUStringNumber<number_t>*>(this));
- }
- operator std::u16string_view() const { return std::u16string_view(buf, length); }
- sal_Unicode buf[nBufSize];
- sal_Int32 length;
-};
-
template<>
struct OUStringNumber< int >
- : public OUStringNumberBase<int, RTL_USTR_MAX_VALUEOFINT32>
+ : public StringNumberBase<sal_Unicode, int, RTL_USTR_MAX_VALUEOFINT32>
{
OUStringNumber(number_t i, sal_Int16 radix) { length = rtl_ustr_valueOfInt32(buf, i, radix); }
};
template<>
struct OUStringNumber< long long >
- : public OUStringNumberBase<long long, RTL_USTR_MAX_VALUEOFINT64>
+ : public StringNumberBase<sal_Unicode, long long, RTL_USTR_MAX_VALUEOFINT64>
{
OUStringNumber(number_t i, sal_Int16 radix) { length = rtl_ustr_valueOfInt64(buf, i, radix); }
};
template<>
struct OUStringNumber< unsigned long long >
- : public OUStringNumberBase<unsigned long long, RTL_USTR_MAX_VALUEOFUINT64>
+ : public StringNumberBase<sal_Unicode, unsigned long long, RTL_USTR_MAX_VALUEOFUINT64>
{
OUStringNumber(number_t i, sal_Int16 radix) { length = rtl_ustr_valueOfUInt64(buf, i, radix); }
};
template<>
struct OUStringNumber< float >
- : public OUStringNumberBase<float, RTL_USTR_MAX_VALUEOFFLOAT>
+ : public StringNumberBase<sal_Unicode, float, RTL_USTR_MAX_VALUEOFFLOAT>
{
OUStringNumber(number_t f) { length = rtl_ustr_valueOfFloat(buf, f); }
};
template<>
struct OUStringNumber< double >
- : public OUStringNumberBase<double, RTL_USTR_MAX_VALUEOFDOUBLE>
+ : public StringNumberBase<sal_Unicode, double, RTL_USTR_MAX_VALUEOFDOUBLE>
{
OUStringNumber(number_t d) { length = rtl_ustr_valueOfDouble(buf, d); }
};
-template< typename T >
-struct ToStringHelper< OUStringNumber< T > >
- {
- static std::size_t length( const OUStringNumber< T >& n ) { return n.length; }
- static sal_Unicode* addData( sal_Unicode* buffer, const OUStringNumber< T >& n ) SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
- static const bool allowOStringConcat = false;
- static const bool allowOUStringConcat = true;
- };
-
-template<> struct ToStringHelper<std::string_view> {
- static constexpr std::size_t length(std::string_view s) { return s.size(); }
-
- static char * addData(char * buffer, std::string_view s) SAL_RETURNS_NONNULL
- { return addDataHelper(buffer, s.data(), s.size()); }
-
- static constexpr bool allowOStringConcat = true;
- static constexpr bool allowOUStringConcat = false;
+template< typename C, typename T, std::size_t nBufSize >
+struct ToStringHelper< StringNumberBase< C, T, nBufSize > >
+{
+ static std::size_t length( const StringNumberBase< C, T, nBufSize >& n ) { return n.length; }
+ C* operator()( C* buffer, const StringNumberBase< C, T, nBufSize >& n ) const SAL_RETURNS_NONNULL { return addDataHelper( buffer, n.buf, n.length ); }
};
-template<> struct ToStringHelper<std::u16string_view> {
- static constexpr std::size_t length(std::u16string_view s) { return s.size(); }
+template<typename T> struct ToStringHelper<OStringNumber<T>> : public ToStringHelper<typename OStringNumber<T>::base_t> {};
+template<typename T> struct ToStringHelper<OUStringNumber<T>> : public ToStringHelper<typename OUStringNumber<T>::base_t> {};
- static sal_Unicode * addData(sal_Unicode * buffer, std::u16string_view s) SAL_RETURNS_NONNULL
- { return addDataHelper(buffer, s.data(), s.size()); }
+template<typename C> struct ToStringHelper<std::basic_string_view<C>> {
+ static constexpr std::size_t length(std::basic_string_view<C> s) { return s.size(); }
- static constexpr bool allowOStringConcat = false;
- static constexpr bool allowOUStringConcat = true;
+ C * operator()(C * buffer, std::basic_string_view<C> s) const SAL_RETURNS_NONNULL
+ { return addDataHelper(buffer, s.data(), s.size()); }
};
-// An internal marker class used by OString::Concat:
-struct OStringConcatMarker {};
+// An internal marker class used by O(U)String::Concat:
+template<typename C> struct StringConcatMarker {};
-template<> struct ToStringHelper<OStringConcatMarker> {
- static constexpr std::size_t length(OStringConcatMarker) { return 0; }
+template<typename C> struct ToStringHelper<StringConcatMarker<C>> {
+ static constexpr std::size_t length(StringConcatMarker<C>) { return 0; }
- static constexpr char * addData(char * buffer, OStringConcatMarker) SAL_RETURNS_NONNULL
+ constexpr C * operator()(C * buffer, StringConcatMarker<C>) const SAL_RETURNS_NONNULL
{ return buffer; }
-
- static constexpr bool allowOStringConcat = true;
- static constexpr bool allowOUStringConcat = false;
};
-// An internal marker class used by OUString::Concat:
-struct OUStringConcatMarker {};
-
-template<> struct ToStringHelper<OUStringConcatMarker> {
- static constexpr std::size_t length(OUStringConcatMarker) { return 0; }
-
- static constexpr sal_Unicode * addData(sal_Unicode * buffer, OUStringConcatMarker)
- SAL_RETURNS_NONNULL
- { return buffer; }
-
- static constexpr bool allowOStringConcat = false;
- static constexpr bool allowOUStringConcat = true;
-};
+using OStringConcatMarker = StringConcatMarker<char>;
+using OUStringConcatMarker = StringConcatMarker<sal_Unicode>;
} // namespace
diff --git a/include/rtl/ustrbuf.hxx b/include/rtl/ustrbuf.hxx
index c5d6b2e9ee1b..af7d0d0d9ef6 100644
--- a/include/rtl/ustrbuf.hxx
+++ b/include/rtl/ustrbuf.hxx
@@ -242,8 +242,8 @@ public:
@overload
@internal
*/
- template< typename T >
- OUStringBuffer( OUStringNumber< T >&& n )
+ template< typename T, std::size_t N >
+ OUStringBuffer( StringNumberBase< sal_Unicode, T, N >&& n )
: pData(NULL)
, nCapacity( n.length + 16 )
{
@@ -380,8 +380,8 @@ public:
}
/** @overload @internal */
- template<typename T>
- OUStringBuffer & operator =(OUStringNumber<T> && n)
+ template<typename T, std::size_t N>
+ OUStringBuffer & operator =(StringNumberBase<sal_Unicode, T, N> && n)
{
*this = OUStringBuffer( std::move( n ) );
return *this;
@@ -722,8 +722,8 @@ public:
@overload
@internal
*/
- template< typename T >
- OUStringBuffer& append( OUStringNumber< T >&& c )
+ template< typename T, std::size_t N >
+ OUStringBuffer& append( StringNumberBase< sal_Unicode, T, N >&& c )
{
return append( c.buf, c.length );
}
@@ -1767,11 +1767,8 @@ private:
template<> struct ToStringHelper<OUStringBuffer> {
static std::size_t length(OUStringBuffer const & s) { return s.getLength(); }
- static sal_Unicode * addData(sal_Unicode * buffer, OUStringBuffer const & s) SAL_RETURNS_NONNULL
+ sal_Unicode * operator()(sal_Unicode * buffer, OUStringBuffer const & s) const SAL_RETURNS_NONNULL
{ return addDataHelper(buffer, s.getStr(), s.getLength()); }
-
- static constexpr bool allowOStringConcat = false;
- static constexpr bool allowOUStringConcat = true;
};
#endif
diff --git a/include/rtl/ustring.hxx b/include/rtl/ustring.hxx
index cddba5dfadd5..69575289f6f5 100644
--- a/include/rtl/ustring.hxx
+++ b/include/rtl/ustring.hxx
@@ -502,8 +502,8 @@ public:
@overload
@internal
*/
- template< typename T >
- OUString( OUStringNumber< T >&& n )
+ template< typename T, std::size_t N >
+ OUString( StringNumberBase< sal_Unicode, T, N >&& n )
: OUString( n.buf, n.length )
{}
#endif
@@ -638,8 +638,8 @@ public:
}
template<std::size_t N> OUString & operator =(OUStringLiteral<N> &&) = delete;
- template<typename T>
- OUString & operator =(OUStringNumber<T> && n) {
+ template <typename T, std::size_t N>
+ OUString & operator =(StringNumberBase<sal_Unicode, T, N> && n) {
// n.length should never be zero, so no need to add an optimization for that case
rtl_uString_newFromStr_WithLength(&pData, n.buf, n.length);
return *this;
@@ -770,8 +770,8 @@ public:
@overload
@internal
*/
- template< typename T >
- OUString& operator+=( OUStringNumber< T >&& n ) & {
+ template< typename T, std::size_t N >
+ OUString& operator+=( StringNumberBase< sal_Unicode, T, N >&& n ) & {
sal_Int32 l = n.length;
if( l == 0 )
return *this;
@@ -782,8 +782,8 @@ public:
pData->length = l;
return *this;
}
- template<typename T> void operator +=(
- OUStringNumber<T> &&) && = delete;
+ template<typename T, std::size_t N> void operator +=(
+ StringNumberBase<sal_Unicode, T, N> &&) && = delete;
#endif
/**
@@ -3301,16 +3301,14 @@ public:
//
// would not compile):
template<typename T> [[nodiscard]] static
- typename std::enable_if_t<
- ToStringHelper<T>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T>>
+ OUStringConcat<OUStringConcatMarker, T>
Concat(T const & value) { return OUStringConcat<OUStringConcatMarker, T>({}, value); }
// This overload is needed so that an argument of type 'char const[N]' ends up as
// 'OUStringConcat<rtl::OUStringConcatMarker, char const[N]>' rather than as
// 'OUStringConcat<rtl::OUStringConcatMarker, char[N]>':
template<typename T, std::size_t N> [[nodiscard]] static
- typename std::enable_if_t<
- ToStringHelper<T[N]>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T[N]>>
+ OUStringConcat<OUStringConcatMarker, T[N]>
Concat(T (& value)[N]) { return OUStringConcat<OUStringConcatMarker, T[N]>({}, value); }
#endif
@@ -3365,24 +3363,20 @@ inline bool operator !=(StringConcatenation<char16_t> const & lhs, OUString cons
*/
template<>
struct ToStringHelper< OUString >
- {
+{
static std::size_t length( const OUString& s ) { return s.getLength(); }
- static sal_Unicode* addData( sal_Unicode* buffer, const OUString& s ) { return addDataHelper( buffer, s.getStr(), s.getLength()); }
- static const bool allowOStringConcat = false;
- static const bool allowOUStringConcat = true;
- };
+ sal_Unicode* operator() ( sal_Unicode* buffer, const OUString& s ) const { return addDataHelper( buffer, s.getStr(), s.getLength()); }
+};
/**
@internal
*/
template<std::size_t N>
struct ToStringHelper< OUStringLiteral<N> >
- {
+{
static std::size_t length( const OUStringLiteral<N>& str ) { return str.getLength(); }
- static sal_Unicode* addData( sal_Unicode* buffer, const OUStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
- static const bool allowOStringConcat = false;
- static const bool allowOUStringConcat = true;
- };
+ sal_Unicode* operator()( sal_Unicode* buffer, const OUStringLiteral<N>& str ) const { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
+};
/**
@internal