diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2022-10-12 16:23:33 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2022-10-13 07:18:41 +0200 |
commit | af2879e434fa0dc6b2a626617ed865e4f66eb5ad (patch) | |
tree | bb25da5b207884ab9fd8d1c49d8dee18b9f1ad12 | |
parent | b3869749719288e6d1951030f07dc3fbccc0c222 (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.cxx | 1 | ||||
-rw-r--r-- | compilerplugins/clang/stringconcatauto.cxx | 8 | ||||
-rw-r--r-- | compilerplugins/clang/stringview.cxx | 7 | ||||
-rw-r--r-- | compilerplugins/clang/test/stringconcatauto.cxx | 12 | ||||
-rw-r--r-- | compilerplugins/clang/test/stringview.cxx | 4 | ||||
-rw-r--r-- | include/rtl/strbuf.hxx | 19 | ||||
-rw-r--r-- | include/rtl/string.hxx | 34 | ||||
-rw-r--r-- | include/rtl/stringconcat.hxx | 396 | ||||
-rw-r--r-- | include/rtl/ustrbuf.hxx | 17 | ||||
-rw-r--r-- | include/rtl/ustring.hxx | 38 |
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 |