codemaker/source/cppumaker/cppumaker.cxx |   13 ++-
 codemaker/source/cppumaker/dumputils.cxx |    5 -
 codemaker/source/cppumaker/dumputils.hxx |    2 
 codemaker/source/javamaker/javamaker.cxx |   13 ++-
 include/o3tl/string_view.hxx             |   44 ++++++++++++
 o3tl/qa/test-string_view.cxx             |  107 +++++++++++++++++++++++++++++++
 sal/osl/all/debugbase.cxx                |    3 
 7 files changed, 171 insertions(+), 16 deletions(-)

New commits:
commit 2bf56582475179faa9d71573532a0d416cb64bfc
Author:     Noel Grandin <[email protected]>
AuthorDate: Fri Apr 8 13:49:01 2022 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Sat Apr 9 09:08:56 2022 +0200

    add a more complete o3tl::getToken
    
    so we avoid OUString copying (mostly when doing stuff like parsing
    numbers of out of strings)
    
    Change-Id: I4ef6ac23671c0b40807a22158e655e92dfad4af6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132730
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/codemaker/source/cppumaker/cppumaker.cxx 
b/codemaker/source/cppumaker/cppumaker.cxx
index 384e2b5aa079..b2556655b361 100644
--- a/codemaker/source/cppumaker/cppumaker.cxx
+++ b/codemaker/source/cppumaker/cppumaker.cxx
@@ -32,6 +32,7 @@
 #include <sal/main.h>
 #include <sal/types.h>
 #include <unoidl/unoidl.hxx>
+#include <o3tl/string_view.hxx>
 
 #include "cppuoptions.hxx"
 #include "cpputype.hxx"
@@ -57,13 +58,13 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) {
         if (options.isValid("-T")) {
             OUString names(b2u(options.getOption("-T")));
             for (sal_Int32 i = 0; i != -1;) {
-                OUString name(names.getToken(0, ';', i));
-                if (!name.isEmpty()) {
+                std::u16string_view name(o3tl::getToken(names, 0, ';', i));
+                if (!name.empty()) {
                     produce(
-                        (name == "*"
-                         ? ""
-                         : name.endsWith(".*")
-                         ? name.copy(0, name.getLength() - std::strlen(".*"))
+                        OUString(name == u"*"
+                         ? u""
+                         : o3tl::ends_with(name, u".*")
+                         ? name.substr(0, name.size() - std::strlen(".*"))
                          : name),
                         typeMgr, generated, options);
                 }
diff --git a/codemaker/source/cppumaker/dumputils.cxx 
b/codemaker/source/cppumaker/dumputils.cxx
index 8524b1962ce2..2a3e809e70f3 100644
--- a/codemaker/source/cppumaker/dumputils.cxx
+++ b/codemaker/source/cppumaker/dumputils.cxx
@@ -24,17 +24,18 @@
 
 #include <rtl/ustring.hxx>
 #include <sal/types.h>
+#include <o3tl/string_view.hxx>
 
 
 namespace codemaker::cppumaker {
 
 bool dumpNamespaceOpen(
-    FileStream & out, OUString const & entityName, bool fullModuleType)
+    FileStream & out, std::u16string_view entityName, bool fullModuleType)
 {
     bool bOutput = false;
     bool bFirst = true;
     for (sal_Int32 i = 0; i >= 0;) {
-        OUString id(entityName.getToken(0, '.', i));
+        std::u16string_view id(o3tl::getToken(entityName, 0, '.', i));
         if (fullModuleType || i >= 0) {
             if (!bFirst) {
                 out << " ";
diff --git a/codemaker/source/cppumaker/dumputils.hxx 
b/codemaker/source/cppumaker/dumputils.hxx
index 2fcd708c43fb..24e5bae3bede 100644
--- a/codemaker/source/cppumaker/dumputils.hxx
+++ b/codemaker/source/cppumaker/dumputils.hxx
@@ -30,7 +30,7 @@ class FileStream;
 
 namespace codemaker::cppumaker
 {
-bool dumpNamespaceOpen(FileStream& out, rtl::OUString const& entityName, bool 
fullModuleType);
+bool dumpNamespaceOpen(FileStream& out, std::u16string_view entityName, bool 
fullModuleType);
 
 bool dumpNamespaceClose(FileStream& out, std::u16string_view entityName, bool 
fullModuleType);
 
diff --git a/codemaker/source/javamaker/javamaker.cxx 
b/codemaker/source/javamaker/javamaker.cxx
index 044292bf6b8f..ee376c8cc484 100644
--- a/codemaker/source/javamaker/javamaker.cxx
+++ b/codemaker/source/javamaker/javamaker.cxx
@@ -32,6 +32,7 @@
 #include <sal/main.h>
 #include <sal/types.h>
 #include <unoidl/unoidl.hxx>
+#include <o3tl/string_view.hxx>
 
 #include "javaoptions.hxx"
 #include "javatype.hxx"
@@ -57,13 +58,13 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) {
         if (options.isValid("-T")) {
             OUString names(b2u(options.getOption("-T")));
             for (sal_Int32 i = 0; i != -1;) {
-                OUString name(names.getToken(0, ';', i));
-                if (!name.isEmpty()) {
+                std::u16string_view name(o3tl::getToken(names, 0, ';', i));
+                if (!name.empty()) {
                     produce(
-                        (name == "*"
-                         ? ""
-                         : name.endsWith(".*")
-                         ? name.copy(0, name.getLength() - std::strlen(".*"))
+                        OUString(name == u"*"
+                         ? u""
+                         : o3tl::ends_with(name, u".*")
+                         ? name.substr(0, name.size() - std::strlen(".*"))
                          : name),
                         typeMgr, generated, options);
                 }
diff --git a/include/o3tl/string_view.hxx b/include/o3tl/string_view.hxx
index b14258c14d39..d9fc84a0d18b 100644
--- a/include/o3tl/string_view.hxx
+++ b/include/o3tl/string_view.hxx
@@ -59,6 +59,50 @@ inline std::string_view getToken(std::string_view sv, char 
delimiter, std::size_
     return t;
 }
 
+// Similar to OUString::getToken
+inline std::u16string_view getToken(std::u16string_view pStr, sal_Int32 
nToken, sal_Unicode cTok,
+                                    sal_Int32& rnIndex)
+{
+    assert(rnIndex <= static_cast<sal_Int32>(pStr.size()));
+
+    // Return an empty string and set rnIndex to -1 if either nToken or 
rnIndex is
+    // negative:
+    if (rnIndex >= 0 && nToken >= 0)
+    {
+        const sal_Unicode* pOrgCharStr = pStr.data();
+        const sal_Unicode* pCharStr = pOrgCharStr + rnIndex;
+        sal_Int32 nLen = pStr.size() - rnIndex;
+        sal_Int32 nTokCount = 0;
+        const sal_Unicode* pCharStrStart = pCharStr;
+        while (nLen > 0)
+        {
+            if (*pCharStr == cTok)
+            {
+                nTokCount++;
+
+                if (nTokCount > nToken)
+                    break;
+                if (nTokCount == nToken)
+                    pCharStrStart = pCharStr + 1;
+            }
+
+            pCharStr++;
+            nLen--;
+        }
+        if (nTokCount >= nToken)
+        {
+            if (nLen > 0)
+                rnIndex = pCharStr - pOrgCharStr + 1;
+            else
+                rnIndex = -1;
+            return std::u16string_view(pCharStrStart, pCharStr - 
pCharStrStart);
+        }
+    }
+
+    rnIndex = -1;
+    return std::u16string_view();
+}
+
 // Implementations of C++20 std::basic_string_view::starts_with and
 // std::basic_string_view::ends_with, until we can use those directly on all 
platforms:
 template <typename charT, typename traits = std::char_traits<charT>>
diff --git a/o3tl/qa/test-string_view.cxx b/o3tl/qa/test-string_view.cxx
index 28ea5a2e99b0..80f9bd9e13fd 100644
--- a/o3tl/qa/test-string_view.cxx
+++ b/o3tl/qa/test-string_view.cxx
@@ -15,6 +15,7 @@
 #include <cppunit/TestFixture.h>
 #include <cppunit/extensions/HelperMacros.h>
 
+#include <o3tl/safeint.hxx>
 #include <o3tl/string_view.hxx>
 #include <rtl/string.hxx>
 #include <rtl/ustring.hxx>
@@ -61,6 +62,7 @@ private:
     CPPUNIT_TEST(testEndsWith);
     CPPUNIT_TEST(testEndsWithRest);
     CPPUNIT_TEST(testEqualsIgnoreAsciiCase);
+    CPPUNIT_TEST(testGetToken);
     CPPUNIT_TEST_SUITE_END();
 
     void testStartsWith()
@@ -597,6 +599,111 @@ private:
         CPPUNIT_ASSERT_GREATER(0, o3tl::compareToIgnoreAsciiCase(u"zest"sv, 
u"test"sv));
         CPPUNIT_ASSERT_LESS(0, o3tl::compareToIgnoreAsciiCase(u"test"sv, 
u"test2"sv));
     }
+
+    void testGetToken()
+    {
+        {
+            OUString suTokenStr;
+            sal_Int32 nIndex = 0;
+            do
+            {
+                o3tl::getToken(suTokenStr, 0, ';', nIndex);
+            } while (nIndex >= 0);
+            // should not GPF
+        }
+        {
+            OUString suTokenStr("a;b");
+
+            sal_Int32 nIndex = 0;
+
+            std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, ';', 
nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'a'", 
std::u16string_view(u"a"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'b'", 
std::u16string_view(u"b"),
+                                         suToken);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", 
static_cast<sal_Int32>(-1),
+                                         nIndex);
+        }
+        {
+            std::u16string_view suTokenStr(u"a;b.c");
+
+            sal_Int32 nIndex = 0;
+
+            std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, ';', 
nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'a'", 
std::u16string_view(u"a"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'b'", 
std::u16string_view(u"b"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'c'", 
std::u16string_view(u"c"),
+                                         suToken);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", 
static_cast<sal_Int32>(-1),
+                                         nIndex);
+        }
+        {
+            std::u16string_view suTokenStr(u"a;;b");
+
+            sal_Int32 nIndex = 0;
+
+            std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, ';', 
nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'a'", 
std::u16string_view(u"a"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+            CPPUNIT_ASSERT_MESSAGE("Token should be empty", suToken.empty());
+
+            suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'b'", 
std::u16string_view(u"b"),
+                                         suToken);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", 
static_cast<sal_Int32>(-1),
+                                         nIndex);
+        }
+        {
+            std::u16string_view suTokenStr(u"longer.then.ever.");
+
+            sal_Int32 nIndex = 0;
+
+            std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, '.', 
nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be 'longer'", 
std::u16string_view(u"longer"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be 'then'", 
std::u16string_view(u"then"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be 'ever'", 
std::u16string_view(u"ever"),
+                                         suToken);
+
+            suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+            CPPUNIT_ASSERT_MESSAGE("Token should be empty", suToken.empty());
+
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", 
static_cast<sal_Int32>(-1),
+                                         nIndex);
+        }
+        {
+            std::u16string_view ab(u"ab");
+            sal_Int32 n = 0;
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("token should be 'ab'", ab, 
o3tl::getToken(ab, 0, '-', n));
+            CPPUNIT_ASSERT_EQUAL_MESSAGE("n should be -1", 
static_cast<sal_Int32>(-1), n);
+            CPPUNIT_ASSERT_MESSAGE("token should be empty", o3tl::getToken(ab, 
0, '-', n).empty());
+        }
+        {
+            std::u16string_view suTokenStr;
+            auto pTokenStr = suTokenStr.data();
+            sal_uInt64 n64 = reinterpret_cast<sal_uInt64>(pTokenStr) / 
sizeof(sal_Unicode);
+            // Point either to 0x0, or to some random address -4GiB away from 
this string
+            sal_Int32 n = n64 > o3tl::make_unsigned(SAL_MAX_INT32) ? 
-SAL_MAX_INT32
+                                                                   : 
-static_cast<sal_Int32>(n64);
+            o3tl::getToken(suTokenStr, 0, ';', n);
+            // should not GPF with negative index
+        }
+    }
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
diff --git a/sal/osl/all/debugbase.cxx b/sal/osl/all/debugbase.cxx
index 208fa3e92a92..59848a883c9d 100644
--- a/sal/osl/all/debugbase.cxx
+++ b/sal/osl/all/debugbase.cxx
@@ -23,6 +23,7 @@
 #include <osl/process.h>
 #include <osl/diagnose.hxx>
 #include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
 
 #include <algorithm>
 #include <vector>
@@ -42,7 +43,7 @@ struct StaticDebugBaseAddressFilter
             sal_Int32 nIndex = 0;
             do {
                 vec.push_back( OUStringToOString(
-                                   str.getToken( 0, ';', nIndex ),
+                                   o3tl::getToken(str, 0, ';', nIndex ),
                                    RTL_TEXTENCODING_ASCII_US ) );
             }
             while (nIndex >= 0);

Reply via email to