Some more string_view use, add o3tl::starts/ends_with
...until those C++20 string_view member functions are generally available (the
fallback implementations are taken directly from the C++20 spec).
(In ParseMathMLAttributeLengthValue in starmath/source/mathml/mathmlattr.cxx,
returning nIdx + 2 instead of nIdx + 1 for the single-character u'%' case was
presumably a typo, but which was harmless as the return value was only checked
for <= 0, and has now been turned into a bool.)
Change-Id: Ib441e474c515f016a4d81bb39f7821dfe0356499
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122322
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
diff --git a/include/o3tl/string_view.hxx b/include/o3tl/string_view.hxx
index 5ebbb0b..b66ba11 100644
--- a/include/o3tl/string_view.hxx
+++ b/include/o3tl/string_view.hxx
@@ -13,6 +13,7 @@
#include <cassert>
#include <cstddef>
#include <string>
#include <string_view>
#include <rtl/ustring.h>
@@ -46,6 +47,66 @@ inline std::string_view getToken(std::string_view sv, char delimiter, std::size_
}
return t;
}
// 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>>
constexpr bool starts_with(std::basic_string_view<charT, traits> sv,
std::basic_string_view<charT, traits> x) noexcept
{
#if defined __cpp_lib_starts_ends_with
return sv.starts_with(x);
#else
return sv.substr(0, x.size()) == x;
#endif
}
template <typename charT, typename traits = std::char_traits<charT>>
constexpr bool starts_with(std::basic_string_view<charT, traits> sv, charT x) noexcept
{
#if defined __cpp_lib_starts_ends_with
return sv.starts_with(x);
#else
return !sv.empty() && traits::eq(sv.front(), x);
#endif
}
template <typename charT, typename traits = std::char_traits<charT>>
constexpr bool starts_with(std::basic_string_view<charT, traits> sv, charT const* x)
{
#if defined __cpp_lib_starts_ends_with
return sv.starts_with(x);
#else
return starts_with(sv, std::basic_string_view<charT, traits>(x));
#endif
}
template <typename charT, typename traits = std::char_traits<charT>>
constexpr bool ends_with(std::basic_string_view<charT, traits> sv,
std::basic_string_view<charT, traits> x) noexcept
{
#if defined __cpp_lib_ends_ends_with
return sv.ends_with(x);
#else
return sv.size() >= x.size()
&& sv.compare(sv.size() - x.size(), std::basic_string_view<charT, traits>::npos, x) == 0;
#endif
}
template <typename charT, typename traits = std::char_traits<charT>>
constexpr bool ends_with(std::basic_string_view<charT, traits> sv, charT x) noexcept
{
#if defined __cpp_lib_ends_ends_with
return sv.ends_with(x);
#else
return !sv.empty() && traits::eq(sv.back(), x);
#endif
}
template <typename charT, typename traits = std::char_traits<charT>>
constexpr bool ends_with(std::basic_string_view<charT, traits> sv, charT const* x)
{
#if defined __cpp_lib_ends_ends_with
return sv.ends_with(x);
#else
return ends_with(sv, std::basic_string_view<charT, traits>(x));
#endif
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/starmath/inc/mathml/mathmlattr.hxx b/starmath/inc/mathml/mathmlattr.hxx
index f999f28..16161fb 100644
--- a/starmath/inc/mathml/mathmlattr.hxx
+++ b/starmath/inc/mathml/mathmlattr.hxx
@@ -9,6 +9,10 @@
#pragma once
#include <sal/config.h>
#include <string_view>
#include <rtl/ustring.hxx>
#include <sal/types.h>
#include <tools/fract.hxx>
@@ -44,7 +48,7 @@ struct MathMLAttributeLengthValue
}
};
sal_Int32 ParseMathMLAttributeLengthValue(const OUString& rStr, MathMLAttributeLengthValue& rV);
bool ParseMathMLAttributeLengthValue(std::u16string_view rStr, MathMLAttributeLengthValue& rV);
// MathML 3: 3.2.2 Mathematics style attributes common to token elements
// <https://www.w3.org/TR/MathML3/chapter3.html#presm.commatt>
diff --git a/starmath/source/mathml/mathmlattr.cxx b/starmath/source/mathml/mathmlattr.cxx
index 7da7f94..ce28ec7 100644
--- a/starmath/source/mathml/mathmlattr.cxx
+++ b/starmath/source/mathml/mathmlattr.cxx
@@ -10,14 +10,18 @@
#include <mathmlattr.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <rtl/math.h>
#include <cstddef>
#include <string_view>
#include <unordered_map>
static sal_Int32 ParseMathMLUnsignedNumber(const OUString& rStr, Fraction& rUN)
static std::size_t ParseMathMLUnsignedNumber(std::u16string_view rStr, Fraction& rUN)
{
auto nLen = rStr.getLength();
sal_Int32 nDecimalPoint = -1;
sal_Int32 nIdx;
auto nLen = rStr.length();
std::size_t nDecimalPoint = std::u16string_view::npos;
std::size_t nIdx;
sal_Int64 nom = 0;
sal_Int64 den = 1;
bool validNomDen = true;
@@ -26,8 +30,8 @@ static sal_Int32 ParseMathMLUnsignedNumber(const OUString& rStr, Fraction& rUN)
auto cD = rStr[nIdx];
if (cD == u'.')
{
if (nDecimalPoint >= 0)
return -1;
if (nDecimalPoint != std::u16string_view::npos)
return std::u16string_view::npos;
nDecimalPoint = nIdx;
continue;
}
@@ -36,13 +40,14 @@ static sal_Int32 ParseMathMLUnsignedNumber(const OUString& rStr, Fraction& rUN)
if (validNomDen
&& (o3tl::checked_multiply(nom, sal_Int64(10), nom)
|| o3tl::checked_add(nom, sal_Int64(cD - u'0'), nom)
|| (nDecimalPoint >= 0 && o3tl::checked_multiply(den, sal_Int64(10), den))))
|| (nDecimalPoint != std::u16string_view::npos
&& o3tl::checked_multiply(den, sal_Int64(10), den))))
{
validNomDen = false;
}
}
if (nIdx == 0 || (nIdx == 1 && nDecimalPoint == 0))
return -1;
return std::u16string_view::npos;
// If the input "xx.yyy" can be represented with nom = xx*10^n + yyy and den = 10^n in sal_Int64
// (where n is the length of "yyy"), then use that to create an accurate Fraction (and TODO: we
@@ -54,83 +59,74 @@ static sal_Int32 ParseMathMLUnsignedNumber(const OUString& rStr, Fraction& rUN)
}
else
{
rUN = Fraction(rStr.copy(0, nIdx).toDouble());
rUN = Fraction(
rtl_math_uStringToDouble(rStr.data(), rStr.data() + nIdx, '.', 0, nullptr, nullptr));
}
return nIdx;
}
static sal_Int32 ParseMathMLNumber(const OUString& rStr, Fraction& rN)
static std::size_t ParseMathMLNumber(std::u16string_view rStr, Fraction& rN)
{
if (rStr.isEmpty())
return -1;
if (rStr.empty())
return std::u16string_view::npos;
bool bNegative = (rStr[0] == '-');
sal_Int32 nOffset = bNegative ? 1 : 0;
auto nIdx = ParseMathMLUnsignedNumber(rStr.copy(nOffset), rN);
if (nIdx <= 0 || !rN.IsValid())
return -1;
std::size_t nOffset = bNegative ? 1 : 0;
auto nIdx = ParseMathMLUnsignedNumber(rStr.substr(nOffset), rN);
if (nIdx == std::u16string_view::npos || !rN.IsValid())
return std::u16string_view::npos;
if (bNegative)
rN *= -1;
return nOffset + nIdx;
}
sal_Int32 ParseMathMLAttributeLengthValue(const OUString& rStr, MathMLAttributeLengthValue& rV)
bool ParseMathMLAttributeLengthValue(std::u16string_view rStr, MathMLAttributeLengthValue& rV)
{
auto nIdx = ParseMathMLNumber(rStr, rV.aNumber);
if (nIdx <= 0)
return -1;
OUString sRest = rStr.copy(nIdx);
if (sRest.isEmpty())
if (nIdx == std::u16string_view::npos)
return false;
std::u16string_view sRest = rStr.substr(nIdx);
if (sRest.empty())
{
rV.eUnit = MathMLLengthUnit::None;
return nIdx;
}
if (sRest.startsWith("em"))
if (o3tl::starts_with(sRest, u"em"))
{
rV.eUnit = MathMLLengthUnit::Em;
return nIdx + 2;
}
if (sRest.startsWith("ex"))
if (o3tl::starts_with(sRest, u"ex"))
{
rV.eUnit = MathMLLengthUnit::Ex;
return nIdx + 2;
}
if (sRest.startsWith("px"))
if (o3tl::starts_with(sRest, u"px"))
{
rV.eUnit = MathMLLengthUnit::Px;
return nIdx + 2;
}
if (sRest.startsWith("in"))
if (o3tl::starts_with(sRest, u"in"))
{
rV.eUnit = MathMLLengthUnit::In;
return nIdx + 2;
}
if (sRest.startsWith("cm"))
if (o3tl::starts_with(sRest, u"cm"))
{
rV.eUnit = MathMLLengthUnit::Cm;
return nIdx + 2;
}
if (sRest.startsWith("mm"))
if (o3tl::starts_with(sRest, u"mm"))
{
rV.eUnit = MathMLLengthUnit::Mm;
return nIdx + 2;
}
if (sRest.startsWith("pt"))
if (o3tl::starts_with(sRest, u"pt"))
{
rV.eUnit = MathMLLengthUnit::Pt;
return nIdx + 2;
}
if (sRest.startsWith("pc"))
if (o3tl::starts_with(sRest, u"pc"))
{
rV.eUnit = MathMLLengthUnit::Pc;
return nIdx + 2;
}
if (sRest[0] == u'%')
{
rV.eUnit = MathMLLengthUnit::Percent;
return nIdx + 2;
}
return nIdx;
return true;
}
bool GetMathMLMathvariantValue(const OUString& rStr, MathMLMathvariantValue& rV)
diff --git a/starmath/source/mathml/mathmlimport.cxx b/starmath/source/mathml/mathmlimport.cxx
index e2db20a..7315c96 100644
--- a/starmath/source/mathml/mathmlimport.cxx
+++ b/starmath/source/mathml/mathmlimport.cxx
@@ -1522,7 +1522,7 @@ void SmXMLSpaceContext_Impl::startFastElement(
switch (aIter.getToken())
{
case XML_WIDTH:
if (ParseMathMLAttributeLengthValue(sValue.trim(), aLV) <= 0
if (!ParseMathMLAttributeLengthValue(sValue.trim(), aLV)
|| !lcl_CountBlanks(aLV, &nWide, &nNarrow))
SAL_WARN("starmath", "ignore mspace's width: " << sValue);
break;