Kaydet (Commit) 50057a37 authored tarafından Stephan Bergmann's avatar Stephan Bergmann

Introduce o3tl::string_view.hxx approximation of C++17 <string_view>

...and use it in configmgr/source/writemodfile.hxx

Change-Id: Ie683dc21010ed45cc454ff89bea0376994b351f2
Reviewed-on: https://gerrit.libreoffice.org/36270Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarStephan Bergmann <sbergman@redhat.com>
üst 39038a35
......@@ -149,7 +149,7 @@ void dumpWindowsRegistryKey(HKEY hKey, OUString const & aKeyName, TempFile &aFil
bool bHasNode = false;
sal_Int32 nCloseNode = 0;
writeData(aFileHandle, "<item oor:path=\"");
aFileHandle.writeString("<item oor:path=\"");
for(sal_Int32 nIndex = 0;; ++nIndex)
{
OUString aNextPathPart = aPathAndNodes.getToken(nIndex, '\\');
......@@ -160,13 +160,13 @@ void dumpWindowsRegistryKey(HKEY hKey, OUString const & aKeyName, TempFile &aFil
{
bHasNode = true;
nCloseNode++;
writeData(aFileHandle, "\"><node oor:name=\"");
aFileHandle.writeString("\"><node oor:name=\"");
sal_Int32 nCommandSeparator = aNextPathPart.lastIndexOf('#');
if(nCommandSeparator != -1)
{
OUString aNodeOp = aNextPathPart.copy(nCommandSeparator + 1);
writeAttributeValue(aFileHandle, aNextPathPart.copy(0, nCommandSeparator - 1));
writeData(aFileHandle, "\" oor:op=\"");
aFileHandle.writeString("\" oor:op=\"");
writeAttributeValue(aFileHandle, aNodeOp);
}
else
......@@ -176,33 +176,34 @@ void dumpWindowsRegistryKey(HKEY hKey, OUString const & aKeyName, TempFile &aFil
}
else
{
writeAttributeValue(aFileHandle, "/" + aNextPathPart);
writeAttributeValue(
aFileHandle, OUString("/" + aNextPathPart));
}
}
else
{
writeData(aFileHandle, "\">");
aFileHandle.writeString("\">");
break;
}
}
writeData(aFileHandle, "<prop oor:name=\"");
aFileHandle.writeString("<prop oor:name=\"");
writeAttributeValue(aFileHandle, aProp);
writeData(aFileHandle, "\"");
aFileHandle.writeString("\"");
if(!aType.isEmpty())
{
writeData(aFileHandle, " oor:type=\"");
aFileHandle.writeString(" oor:type=\"");
writeAttributeValue(aFileHandle, aType);
writeData(aFileHandle, "\"");
aFileHandle.writeString("\"");
}
if(bFinal)
writeData(aFileHandle, " oor:finalized=\"true\"");
writeData(aFileHandle, "><value>");
aFileHandle.writeString(" oor:finalized=\"true\"");
aFileHandle.writeString("><value>");
writeValueContent(aFileHandle, aValue);
writeData(aFileHandle, "</value></prop>");
aFileHandle.writeString("</value></prop>");
for(; nCloseNode > 0; nCloseNode--)
writeData(aFileHandle, "</node>");
writeData(aFileHandle, "</item>\n");
aFileHandle.writeString("</node>");
aFileHandle.writeString("</item>\n");
}
RegCloseKey(hCurKey);
}
......@@ -235,14 +236,13 @@ bool dumpWindowsRegistry(OUString* pFileURL, WinRegType eType)
"cannot create temporary file");
}
aFileHandle.url = *pFileURL;
writeData(
aFileHandle,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
" xmlns:oor=\"http://openoffice.org/2001/registry\""
" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
aFileHandle.writeString(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
" xmlns:oor=\"http://openoffice.org/2001/registry\""
" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
dumpWindowsRegistryKey(hKey, "", aFileHandle);
writeData(aFileHandle, "</oor:items>");
aFileHandle.writeString("</oor:items>");
oslFileError e = aFileHandle.closeWithoutUnlink();
if (e != osl_File_E_None)
SAL_WARN("configmgr", "osl_closeFile failed with " << +e);
......
......@@ -20,12 +20,15 @@
#include <sal/config.h>
#include <cassert>
#include <cstddef>
#include <limits>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/uno/XInterface.hpp>
#include <o3tl/string_view.hxx>
#include <osl/file.h>
#include <osl/file.hxx>
#include <rtl/string.h>
......@@ -57,13 +60,11 @@ class Components;
namespace {
OString convertToUtf8(
OUString const & text, sal_Int32 offset, sal_Int32 length)
{
assert(offset <= text.getLength() && text.getLength() - offset >= length);
OString convertToUtf8(o3tl::u16string_view text) {
OString s;
assert(text.size() <= sal_uInt32(std::numeric_limits<sal_Int32>::max()));
if (!rtl_convertUStringToString(
&s.pData, text.pData->buffer + offset, length,
&s.pData, text.data(), text.size(),
RTL_TEXTENCODING_UTF8,
(RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
......@@ -139,43 +140,38 @@ oslFileError TempFile::flush() {
return e;
}
void TempFile::writeString(char const *begin, sal_Int32 length) {
buffer.append(begin, length);
void TempFile::writeString(o3tl::string_view text) {
buffer.append(text.data(), text.size());
if (buffer.getLength() > 0x10000)
flush();
}
namespace {
void writeData_(TempFile &handle, char const * begin, sal_Int32 length) {
assert(length >= 0);
handle.writeString(begin, length);
}
void writeValueContent_(TempFile &, bool) = delete;
// silence loplugin:salbool
void writeValueContent_(TempFile &handle, sal_Bool value) {
if (value) {
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("true"));
handle.writeString("true");
} else {
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("false"));
handle.writeString("false");
}
}
void writeValueContent_(TempFile &handle, sal_Int16 value) {
writeData(handle, OString::number(value));
handle.writeString(OString::number(value));
}
void writeValueContent_(TempFile &handle, sal_Int32 value) {
writeData(handle, OString::number(value));
handle.writeString(OString::number(value));
}
void writeValueContent_(TempFile &handle, sal_Int64 value) {
writeData(handle, OString::number(value));
handle.writeString(OString::number(value));
}
void writeValueContent_(TempFile &handle, double value) {
writeData(handle, OString::number(value));
handle.writeString(OString::number(value));
}
void writeValueContent_(TempFile &handle, const OUString& value) {
......@@ -189,48 +185,49 @@ void writeValueContent_(
static char const hexDigit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
'D', 'E', 'F' };
writeData_(handle, hexDigit + ((value[i] >> 4) & 0xF), 1);
writeData_(handle, hexDigit + (value[i] & 0xF), 1);
handle.writeString(
o3tl::string_view(hexDigit + ((value[i] >> 4) & 0xF), 1));
handle.writeString(o3tl::string_view(hexDigit + (value[i] & 0xF), 1));
}
}
template< typename T > void writeSingleValue(
TempFile &handle, css::uno::Any const & value)
{
writeData_(handle, RTL_CONSTASCII_STRINGPARAM(">"));
handle.writeString(">");
T val = T();
value >>= val;
writeValueContent_(handle, val);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
handle.writeString("</value>");
}
template< typename T > void writeListValue(
TempFile &handle, css::uno::Any const & value)
{
writeData_(handle, RTL_CONSTASCII_STRINGPARAM(">"));
handle.writeString(">");
css::uno::Sequence< T > val;
value >>= val;
for (sal_Int32 i = 0; i < val.getLength(); ++i) {
if (i != 0) {
writeData_(handle, RTL_CONSTASCII_STRINGPARAM(" "));
handle.writeString(" ");
}
writeValueContent_(handle, val[i]);
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
handle.writeString("</value>");
}
template< typename T > void writeItemListValue(
TempFile &handle, css::uno::Any const & value)
{
writeData_(handle, RTL_CONSTASCII_STRINGPARAM(">"));
handle.writeString(">");
css::uno::Sequence< T > val;
value >>= val;
for (sal_Int32 i = 0; i < val.getLength(); ++i) {
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<it>"));
handle.writeString("<it>");
writeValueContent_(handle, val[i]);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</it>"));
handle.writeString("</it>");
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</value>"));
handle.writeString("</value>");
}
void writeValue(TempFile &handle, Type type, css::uno::Any const & value) {
......@@ -284,7 +281,7 @@ void writeValue(TempFile &handle, Type type, css::uno::Any const & value) {
void writeNode(
Components & components, TempFile &handle,
rtl::Reference< Node > const & parent, OUString const & name,
rtl::Reference< Node > const & parent, o3tl::u16string_view name,
rtl::Reference< Node > const & node)
{
static xmlreader::Span const typeNames[] = {
......@@ -308,51 +305,49 @@ void writeNode(
case Node::KIND_PROPERTY:
{
PropertyNode * prop = static_cast< PropertyNode * >(node.get());
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
handle.writeString("<prop oor:name=\"");
writeAttributeValue(handle, name);
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\""));
handle.writeString("\" oor:op=\"fuse\"");
Type type = prop->getStaticType();
Type dynType = getDynamicType(prop->getValue(components));
assert(dynType != TYPE_ERROR);
if (type == TYPE_ANY) {
type = dynType;
if (type != TYPE_NIL) {
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
writeData_(
handle, typeNames[type].begin, typeNames[type].length);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
handle.writeString(" oor:type=\"");
handle.writeString(
o3tl::string_view(
typeNames[type].begin, typeNames[type].length));
handle.writeString("\"");
}
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("><value"));
handle.writeString("><value");
if (dynType == TYPE_NIL) {
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
handle.writeString(" xsi:nil=\"true\"/>");
} else {
writeValue(handle, type, prop->getValue(components));
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</prop>"));
handle.writeString("</prop>");
}
break;
case Node::KIND_LOCALIZED_PROPERTY:
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
handle.writeString("<prop oor:name=\"");
writeAttributeValue(handle, name);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"fuse\">"));
handle.writeString("\" oor:op=\"fuse\">");
for (NodeMap::const_iterator i(node->getMembers().begin());
i != node->getMembers().end(); ++i)
{
writeNode(components, handle, node, i->first, i->second);
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</prop>"));
handle.writeString("</prop>");
break;
case Node::KIND_LOCALIZED_VALUE:
{
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<value"));
if (!name.isEmpty()) {
writeData_(handle, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
handle.writeString("<value");
if (!name.empty()) {
handle.writeString(" xml:lang=\"");
writeAttributeValue(handle, name);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
handle.writeString("\"");
}
Type type = static_cast< LocalizedPropertyNode * >(parent.get())->
getStaticType();
......@@ -363,16 +358,15 @@ void writeNode(
if (type == TYPE_ANY) {
type = dynType;
if (type != TYPE_NIL) {
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM(" oor:type=\""));
writeData_(
handle, typeNames[type].begin, typeNames[type].length);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
handle.writeString(" oor:type=\"");
handle.writeString(
o3tl::string_view(
typeNames[type].begin, typeNames[type].length));
handle.writeString("\"");
}
}
if (dynType == TYPE_NIL) {
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM(" xsi:nil=\"true\"/>"));
handle.writeString(" xsi:nil=\"true\"/>");
} else {
writeValue(handle, type, value);
}
......@@ -380,19 +374,18 @@ void writeNode(
break;
case Node::KIND_GROUP:
case Node::KIND_SET:
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
handle.writeString("<node oor:name=\"");
writeAttributeValue(handle, name);
if (!node->getTemplateName().isEmpty()) { // set member
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"replace"));
handle.writeString("\" oor:op=\"replace");
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\">"));
handle.writeString("\">");
for (NodeMap::const_iterator i(node->getMembers().begin());
i != node->getMembers().end(); ++i)
{
writeNode(components, handle, node, i->first, i->second);
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</node>"));
handle.writeString("</node>");
break;
case Node::KIND_ROOT:
assert(false); // this cannot happen
......@@ -422,48 +415,40 @@ void writeModifications(
if (modifications.children.empty()) {
assert(parent.is());
// components themselves have no parent but must have children
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<item oor:path=\""));
handle.writeString("<item oor:path=\"");
writeAttributeValue(handle, parentPathRepresentation);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\">"));
handle.writeString("\">");
if (node.is()) {
writeNode(components, handle, parent, nodeName, node);
} else {
switch (parent->kind()) {
case Node::KIND_LOCALIZED_PROPERTY:
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("<value"));
handle.writeString("<value");
if (!nodeName.isEmpty()) {
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM(" xml:lang=\""));
handle.writeString(" xml:lang=\"");
writeAttributeValue(handle, nodeName);
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\""));
handle.writeString("\"");
}
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM(" oor:op=\"remove\"/>"));
handle.writeString(" oor:op=\"remove\"/>");
break;
case Node::KIND_GROUP:
assert(
static_cast< GroupNode * >(parent.get())->isExtensible());
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM("<prop oor:name=\""));
handle.writeString("<prop oor:name=\"");
writeAttributeValue(handle, nodeName);
writeData_(
handle,
RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
handle.writeString("\" oor:op=\"remove\"/>");
break;
case Node::KIND_SET:
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM("<node oor:name=\""));
handle.writeString("<node oor:name=\"");
writeAttributeValue(handle, nodeName);
writeData_(
handle,
RTL_CONSTASCII_STRINGPARAM("\" oor:op=\"remove\"/>"));
handle.writeString("\" oor:op=\"remove\"/>");
break;
default:
assert(false); // this cannot happen
break;
}
}
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("</item>\n"));
handle.writeString("</item>\n");
} else {
assert(node.is());
OUString pathRep(
......@@ -496,91 +481,85 @@ void writeModifications(
}
void writeData(TempFile &handle, OString const & text) {
writeData_(handle, text.getStr(), text.getLength());
}
void writeAttributeValue(TempFile &handle, OUString const & value) {
sal_Int32 i = 0;
sal_Int32 j = i;
for (; j < value.getLength(); ++j) {
void writeAttributeValue(TempFile &handle, o3tl::u16string_view value) {
std::size_t i = 0;
std::size_t j = i;
for (; j != value.size(); ++j) {
assert(
value[j] == 0x0009 || value[j] == 0x000A || value[j] == 0x000D ||
(value[j] >= 0x0020 && value[j] != 0xFFFE && value[j] != 0xFFFF));
switch(value[j]) {
case '\x09':
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#9;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&#9;");
i = j + 1;
break;
case '\x0A':
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#xA;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&#xA;");
i = j + 1;
break;
case '\x0D':
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#xD;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&#xD;");
i = j + 1;
break;
case '"':
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&quot;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&quot;");
i = j + 1;
break;
case '&':
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&amp;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&amp;");
i = j + 1;
break;
case '<':
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&lt;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&lt;");
i = j + 1;
break;
default:
break;
}
}
writeData(handle, convertToUtf8(value, i, j - i));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
}
void writeValueContent(TempFile &handle, OUString const & value) {
sal_Int32 i = 0;
sal_Int32 j = i;
for (; j < value.getLength(); ++j) {
sal_Unicode c = value[j];
void writeValueContent(TempFile &handle, o3tl::u16string_view value) {
std::size_t i = 0;
std::size_t j = i;
for (; j != value.size(); ++j) {
char16_t c = value[j];
if ((c < 0x0020 && c != 0x0009 && c != 0x000A && c != 0x000D) ||
c == 0xFFFE || c == 0xFFFF)
{
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(
handle, RTL_CONSTASCII_STRINGPARAM("<unicode oor:scalar=\""));
writeData(
handle, OString::number(c));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("\"/>"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("<unicode oor:scalar=\"");
handle.writeString(OString::number(c));
handle.writeString("\"/>");
i = j + 1;
} else if (c == '\x0D') {
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&#xD;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&#xD;");
i = j + 1;
} else if (c == '&') {
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&amp;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&amp;");
i = j + 1;
} else if (c == '<') {
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&lt;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&lt;");
i = j + 1;
} else if (c == '>') {
// "MUST, for compatibility, be escaped [...] when it appears in the
// string ']]>'":
writeData(handle, convertToUtf8(value, i, j - i));
writeData_(handle, RTL_CONSTASCII_STRINGPARAM("&gt;"));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
handle.writeString("&gt;");
i = j + 1;
}
}
writeData(handle, convertToUtf8(value, i, j - i));
handle.writeString(convertToUtf8(value.substr(i, j - i)));
}
void writeModFile(
......@@ -617,13 +596,11 @@ void writeModFile(
throw css::uno::RuntimeException(
"cannot create temporary file in " + dir);
}
writeData_(
tmp,
RTL_CONSTASCII_STRINGPARAM(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
" xmlns:oor=\"http://openoffice.org/2001/registry\""
" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"));
tmp.writeString(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
" xmlns:oor=\"http://openoffice.org/2001/registry\""
" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
//TODO: Do not write back information about those removed items that did not
// come from the .xcs/.xcu files, anyway (but had been added dynamically
// instead):
......@@ -658,7 +635,7 @@ void writeModFile(
data.getComponents().findNode(Data::NO_LAYER, j->first),
j->second);
}
writeData_(tmp, RTL_CONSTASCII_STRINGPARAM("</oor:items>\n"));
tmp.writeString("</oor:items>\n");
tmp.closeAndRename(url);
}
......
......@@ -21,6 +21,8 @@
#define INCLUDED_CONFIGMGR_SOURCE_WRITEMODFILE_HXX
#include <sal/config.h>
#include <o3tl/string_view.hxx>
#include <rtl/strbuf.hxx>
namespace configmgr {
......@@ -41,16 +43,15 @@ struct TempFile {
#ifdef _WIN32
oslFileError closeWithoutUnlink();
#endif
void writeString(char const *begin, sal_Int32 length);
void writeString(o3tl::string_view text);
private:
TempFile(const TempFile&) = delete;
TempFile& operator=(const TempFile&) = delete;
};
void writeData(TempFile &handle, OString const & text);
void writeAttributeValue(TempFile &handle, OUString const & value);
void writeValueContent(TempFile &handle, OUString const & value);
void writeAttributeValue(TempFile &handle, o3tl::u16string_view value);
void writeValueContent(TempFile &handle, o3tl::u16string_view value);
void writeModFile(
Components & components, OUString const & url, Data const & data);
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef INCLUDED_O3TL_STRING_VIEW_HXX
#define INCLUDED_O3TL_STRING_VIEW_HXX
#include <sal/config.h>
#include <algorithm>
#include <cstddef>
#include <ios>
#include <iterator>
#include <ostream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <config_global.h>
#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include <sal/types.h>
// An approximation of C++17 <string_view>, including implicit conversion
// from rtl::OString and rtl::OUString.
namespace o3tl {
namespace detail {
template<typename T> struct CharPtrDetector {
static constexpr bool ok = false;
};
template<> struct CharPtrDetector<char *> {
static constexpr bool ok = true;
};
template<> struct CharPtrDetector<char const *> {
static constexpr bool ok = true;
};
template<typename T> struct NonConstCharArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct NonConstCharArrayDetector<char [N]> {
static constexpr bool ok = true;
};
template<typename T> struct ConstCharArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct ConstCharArrayDetector<char const[N]> {
static constexpr bool ok = true;
static constexpr std::size_t length = N - 1;
};
template<typename T> struct Char16PtrDetector {
static constexpr bool ok = false;
};
template<> struct Char16PtrDetector<char16_t *> {
static constexpr bool ok = true;
};
template<> struct Char16PtrDetector<char16_t const *> {
static constexpr bool ok = true;
};
template<typename T> struct NonConstChar16ArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct NonConstChar16ArrayDetector<char16_t [N]> {
static constexpr bool ok = true;
};
template<typename T> struct ConstChar16ArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct ConstChar16ArrayDetector<char16_t const[N]> {
static constexpr bool ok = true;
static constexpr std::size_t length = N - 1;
};
template<typename T> struct Char32PtrDetector {
static constexpr bool ok = false;
};
template<> struct Char32PtrDetector<char32_t *> {
static constexpr bool ok = true;
};
template<> struct Char32PtrDetector<char32_t const *> {
static constexpr bool ok = true;
};
template<typename T> struct NonConstChar32ArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct NonConstChar32ArrayDetector<char32_t [N]> {
static constexpr bool ok = true;
};
template<typename T> struct ConstChar32ArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct ConstChar32ArrayDetector<char32_t const[N]> {
static constexpr bool ok = true;
static constexpr std::size_t length = N - 1;
};
template<typename T> struct WcharPtrDetector {
static constexpr bool ok = false;
};
template<> struct WcharPtrDetector<wchar_t *> {
static constexpr bool ok = true;
};
template<> struct WcharPtrDetector<wchar_t const *> {
static constexpr bool ok = true;
};
template<typename T> struct NonConstWcharArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct NonConstWcharArrayDetector<wchar_t [N]> {
static constexpr bool ok = true;
};
template<typename T> struct ConstWcharArrayDetector {
static constexpr bool ok = false;
};
template<std::size_t N> struct ConstWcharArrayDetector<wchar_t const[N]> {
static constexpr bool ok = true;
static constexpr std::size_t length = N - 1;
};
}
#if defined _MSC_VER
#pragma warning(push, 1)
#pragma warning(disable: 4814) // in C++14 'constexpr' will not imply 'const'
#endif
template<typename charT, typename traits = std::char_traits<charT>>
class basic_string_view {
public:
using traits_type = traits;
using value_type = charT;
using pointer = value_type *;
using const_pointer = value_type const *;
using reference = value_type &;
using const_reference = value_type const &;
using const_iterator = const_pointer;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
static constexpr size_type npos = size_type(-1);
constexpr basic_string_view() noexcept: data_(nullptr), size_(0) {}
constexpr basic_string_view(basic_string_view const &) noexcept = default;
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
basic_string_view & operator =(basic_string_view const & other) noexcept
#if defined _MSC_VER && _MSC_VER <= 1900 && !defined __clang__
{
data_ = other.data_;
size_ = other.size_;
return *this;
}
#else
= default;
#endif
// The various character types are handled below in the "LO specifics, to
// make up for traits::length not necessarily being constexpr yet for
// literal arguments" section:
template<typename T = charT> constexpr basic_string_view(
charT const * str,
typename std::enable_if<
!(std::is_same<T, char>::value || std::is_same<T, char16_t>::value
|| std::is_same<T, char32_t>::value
|| std::is_same<T, wchar_t>::value),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(str), size_(traits::length(str)) {}
constexpr basic_string_view(charT const * str, size_type len):
data_(str), size_(len) {}
constexpr const_iterator begin() const noexcept { return data_; }
constexpr const_iterator end() const noexcept { return begin() + size(); }
constexpr const_iterator cbegin() const noexcept { return begin(); }
constexpr const_iterator cend() const noexcept { return end(); }
constexpr const_reverse_iterator rbegin() const noexcept
{ return const_reverse_iterator(end()); }
constexpr const_reverse_iterator rend() const noexcept
{ return const_reverse_iterator(begin()); }
constexpr const_reverse_iterator crbegin() const noexcept
{ return rbegin(); }
constexpr const_reverse_iterator crend() const noexcept { return rend(); }
constexpr size_type size() const noexcept { return size_; }
constexpr size_type length() const noexcept { return size(); }
#if !defined __clang__ || HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type max_size() const noexcept {
#if defined __clang__ // avoid constexpr issues with other, older compilers
(void) this; // loplugin:staticmethods
#endif
return npos - 1;
}
constexpr bool empty() const noexcept { return size_ == 0; }
constexpr const_reference operator [](size_type pos) const {
#if HAVE_CXX14_CONSTEXPR
assert(pos < size());
#endif
return data_[pos];
}
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
const_reference at(size_type pos) const {
if (pos >= size()) {
throw std::out_of_range("o3tl::basic_string_view::at");
}
return operator [](pos);
}
constexpr const_reference front() const {
#if HAVE_CXX14_CONSTEXPR
assert(!empty());
#endif
return operator [](0);
}
constexpr const_reference back() const {
#if HAVE_CXX14_CONSTEXPR
assert(!empty());
#endif
return operator [](size() - 1);
}
constexpr const_pointer data() const noexcept { return data_; }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
void remove_prefix(size_type n) {
assert(n <= size());
data_ += n;
size_ -= n;
}
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
void remove_suffix(size_type n) {
assert(n <= size());
size_ -= n;
}
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
void swap(basic_string_view & s) noexcept {
std::swap(data_, s.data_);
std::swap(size_, s.size_);
}
size_type copy(charT * s, size_type n, size_type pos = 0) const {
if (pos > size()) {
throw std::out_of_range("o3tl::basic_string_view::copy");
}
auto rlen = std::min(n, size_type(size() - pos));
traits::copy(s, data() + pos, rlen);
return rlen;
}
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
basic_string_view substr(size_type pos = 0, size_type n = npos) const {
if (pos > size()) {
throw std::out_of_range("o3tl::basic_string_view::copy");
}
return basic_string_view(
data() + pos, std::min(n, size_type(size() - pos)));
}
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
int compare(basic_string_view s) const noexcept {
auto n = traits::compare(data(), s.data(), std::min(size(), s.size()));
return n == 0
? (size() < s.size() ? -1 : size() == s.size() ? 0 : 1) : n;
}
constexpr int compare(size_type pos1, size_type n1, basic_string_view s)
const
{ return substr(pos1, n1).compare(s); }
constexpr int compare(
size_type pos1, size_type n1, basic_string_view s, size_type pos2,
size_type n2) const
{ return substr(pos1, n1).compare(s.substr(pos2, n2)); }
constexpr int compare(charT const * s) const
{ return compare(basic_string_view(s)); }
constexpr int compare(size_type pos1, size_type n1, charT const * s) const
{ return substr(pos1, n1).compare(s); }
constexpr int compare(
size_type pos1, size_type n1, charT const * s, size_type n2) const
{ return substr(pos1, n1).compare(basic_string_view(s, n2)); }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type find(basic_string_view s, size_type pos = 0) const noexcept {
if (s.size() <= size()) {
for (auto xpos = pos; xpos <= size() - s.size(); ++xpos) {
bool match = true;
for (size_type i = 0; i != s.size(); ++i) {
if (!traits::eq(data_[xpos + i], s.data_[i])) {
match = false;
break;
}
}
if (match) {
return xpos;
}
}
}
return npos;
}
constexpr size_type find(charT c, size_type pos = 0) const noexcept
{ return find(basic_string_view(&c, 1), pos); }
constexpr size_type find(charT const * s, size_type pos, size_type n) const
{ return find(basic_string_view(s, n), pos); }
constexpr size_type find(charT const * s, size_type pos = 0) const
{ return find(basic_string_view(s), pos); }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type rfind(basic_string_view s, size_type pos = npos) const noexcept {
if (s.size() <= size()) {
for (auto xpos = std::min<size_type>(size() - s.size(), pos);;
--xpos)
{
bool match = true;
for (size_type i = 0; i != s.size(); ++i) {
if (!traits::eq(data_[xpos + i], s.data_[i])) {
match = false;
break;
}
}
if (match) {
return xpos;
}
if (xpos == 0) {
break;
}
}
}
return npos;
}
constexpr size_type rfind(charT c, size_type pos = npos) const noexcept
{ return rfind(basic_string_view(&c, 1), pos); }
constexpr size_type rfind(charT const * s, size_type pos, size_type n) const
{ return rfind(basic_string_view(s, n), pos); }
constexpr size_type rfind(charT const * s, size_type pos = npos) const
{ return rfind(basic_string_view(s), pos); }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type find_first_of(basic_string_view s, size_type pos = 0) const
noexcept
{
for (auto xpos = pos; xpos < size(); ++xpos) {
for (size_type i = 0; i != s.size(); ++i) {
if (traits::eq(data_[xpos], s.data_[i])) {
return xpos;
}
}
}
return npos;
}
constexpr size_type find_first_of(charT c, size_type pos = 0) const noexcept
{ return find_first_of(basic_string_view(&c, 1), pos); }
constexpr size_type find_first_of(
charT const * s, size_type pos, size_type n) const
{ return find_first_of(basic_string_view(s, n), pos); }
constexpr size_type find_first_of(charT const * s, size_type pos = 0) const
{ return find_first_of(basic_string_view(s), pos); }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type find_last_of(basic_string_view s, size_type pos = npos) const
noexcept
{
if (!empty()) {
for (auto xpos = std::min<size_type>(size() - 1, pos);; --xpos) {
for (size_type i = 0; i != s.size(); ++i) {
if (traits::eq(data_[xpos], s.data_[i])) {
return xpos;
}
}
if (xpos == 0) {
break;
}
}
}
return npos;
}
constexpr size_type find_last_of(charT c, size_type pos = npos) const
noexcept
{ return find_last_of(basic_string_view(&c, 1), pos); }
constexpr size_type find_last_of(
charT const * s, size_type pos, size_type n) const
{ return find_last_of(basic_string_view(s, n), pos); }
constexpr size_type find_last_of(charT const * s, size_type pos = npos)
const
{ return find_last_of(basic_string_view(s), pos); }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type find_first_not_of(basic_string_view s, size_type pos = 0) const
noexcept
{
for (auto xpos = pos; xpos < size(); ++xpos) {
bool match = true;
for (size_type i = 0; i != s.size(); ++i) {
if (traits::eq(data_[xpos], s.data_[i])) {
match = false;
break;
}
}
if (match) {
return xpos;
}
}
return npos;
}
constexpr size_type find_first_not_of(charT c, size_type pos = 0) const
noexcept
{ return find_first_not_of(basic_string_view(&c, 1), pos); }
constexpr size_type find_first_not_of(
charT const * s, size_type pos, size_type n) const
{ return find_first_not_of(basic_string_view(s, n), pos); }
constexpr size_type find_first_not_of(charT const * s, size_type pos = 0)
const
{ return find_first_not_of(basic_string_view(s), pos); }
#if HAVE_CXX14_CONSTEXPR
constexpr
#endif
size_type find_last_not_of(basic_string_view s, size_type pos = npos) const
noexcept
{
if (!empty()) {
for (auto xpos = std::min<size_type>(size() - 1, pos);; --xpos) {
bool match = true;
for (size_type i = 0; i != s.size(); ++i) {
if (traits::eq(data_[xpos], s.data_[i])) {
match = false;
break;
}
}
if (match) {
return xpos;
}
if (xpos == 0) {
break;
}
}
}
return npos;
}
constexpr size_type find_last_not_of(charT c, size_type pos = npos) const
noexcept
{ return find_last_not_of(basic_string_view(&c, 1), pos); }
constexpr size_type find_last_not_of(
charT const * s, size_type pos, size_type n) const
{ return find_last_not_of(basic_string_view(s, n), pos); }
constexpr size_type find_last_not_of(charT const * s, size_type pos = npos)
const
{ return find_last_not_of(basic_string_view(s), pos); }
// LO specifics:
// For std::basic_string_view, this is provided via a non-explicit
// conversion operator from std::basic_string:
constexpr basic_string_view(std::basic_string<charT, traits> const & s):
data_(s.data()), size_(s.size()) {}
// For std::string_view, this will be provided by a (LIBO_INTERNAL_ONLY)
// non-explicit conversion operator from rtl::OString:
template<typename T = charT> basic_string_view(
OString const & s,
typename std::enable_if<
std::is_same<T, char>::value,
rtl::libreoffice_internal::Dummy>::type = {}):
data_(s.getStr()), size_(s.getLength()) {}
// For std::u16string_view, this will be provided by a (LIBO_INTERNAL_ONLY)
// non-explicit conversion operator from rtl::OUString:
template<typename T = charT> basic_string_view(
OUString const & s,
typename std::enable_if<
std::is_same<T, sal_Unicode>::value,
rtl::libreoffice_internal::Dummy>::type = {}):
data_(s.getStr()), size_(s.getLength()) {}
// For std::u16string_view, this would either be provided by a
// (LIBO_INTERNAL_ONLY) non-explicit conversion operator from
// rtl::OUStringLiteral, or rtl::OUStringLiteral would be given up in favor
// of std::u16string_view anyway (but this constructor also serves to reject
// as ambiguous construction of a o3tl::u16string_view from a narrow string
// literal, which would otherwise go via the above rtl::OUString
// constructor):
template<typename T = charT> constexpr basic_string_view(
OUStringLiteral literal,
typename std::enable_if<
std::is_same<T, sal_Unicode>::value,
rtl::libreoffice_internal::Dummy>::type = {}):
data_(literal.data), size_(literal.size) {}
// LO specifics, to make up for traits::length not necessarily being
// constexpr yet for literal arguments:
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 const & value,
typename std::enable_if<
std::is_same<T2, char>::value && detail::CharPtrDetector<T1>::ok,
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & value,
typename std::enable_if<
(std::is_same<T2, char>::value
&& detail::NonConstCharArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & literal,
typename std::enable_if<
(std::is_same<T2, char>::value
&& detail::ConstCharArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(literal), size_(detail::ConstCharArrayDetector<T1>::length)
{ /*assert(size_ == traits::length(literal);*/ }
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 const & value,
typename std::enable_if<
(std::is_same<T2, char16_t>::value
&& detail::Char16PtrDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & value,
typename std::enable_if<
(std::is_same<T2, char16_t>::value
&& detail::NonConstChar16ArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & literal,
typename std::enable_if<
(std::is_same<T2, char16_t>::value
&& detail::ConstChar16ArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(literal), size_(detail::ConstChar16ArrayDetector<T1>::length)
{ /*assert(size_ == traits::length(literal);*/ }
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 const & value,
typename std::enable_if<
(std::is_same<T2, char32_t>::value
&& detail::Char32PtrDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & value,
typename std::enable_if<
(std::is_same<T2, char32_t>::value
&& detail::NonConstChar32ArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & literal,
typename std::enable_if<
(std::is_same<T2, char32_t>::value
&& detail::ConstChar32ArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(literal), size_(detail::ConstChar32ArrayDetector<T1>::length)
{ /*assert(size_ == traits::length(literal);*/ }
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 const & value,
typename std::enable_if<
(std::is_same<T2, wchar_t>::value
&& detail::WcharPtrDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & value,
typename std::enable_if<
(std::is_same<T2, wchar_t>::value
&& detail::NonConstWcharArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(value), size_(traits::length(value)) {}
template<typename T1, typename T2 = charT> constexpr basic_string_view(
T1 & literal,
typename std::enable_if<
(std::is_same<T2, wchar_t>::value
&& detail::ConstWcharArrayDetector<T1>::ok),
rtl::libreoffice_internal::Dummy>::type = {}):
data_(literal), size_(detail::ConstWcharArrayDetector<T1>::length)
{ /*assert(size_ == traits::length(literal);*/ }
private:
const_pointer data_;
size_type size_;
};
template<class charT, class traits> constexpr bool operator ==(
basic_string_view<charT, traits> x, basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) == 0; }
template<class charT, class traits> constexpr bool operator ==(
basic_string_view<charT, traits> x,
typename std::decay<basic_string_view<charT, traits>>::type y)
noexcept
{ return x.compare(y) == 0; }
template<class charT, class traits> constexpr bool operator ==(
typename std::decay<basic_string_view<charT, traits>>::type x,
basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) == 0; }
template<class charT, class traits> constexpr bool operator !=(
basic_string_view<charT, traits> x, basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) != 0; }
template<class charT, class traits> constexpr bool operator !=(
basic_string_view<charT, traits> x,
typename std::decay<basic_string_view<charT, traits>>::type y)
noexcept
{ return x.compare(y) != 0; }
template<class charT, class traits> constexpr bool operator !=(
typename std::decay<basic_string_view<charT, traits>>::type x,
basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) != 0; }
template<class charT, class traits> constexpr bool operator <(
basic_string_view<charT, traits> x, basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) < 0; }
template<class charT, class traits> constexpr bool operator <(
basic_string_view<charT, traits> x,
typename std::decay<basic_string_view<charT, traits>>::type y)
noexcept
{ return x.compare(y) < 0; }
template<class charT, class traits> constexpr bool operator <(
typename std::decay<basic_string_view<charT, traits>>::type x,
basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) < 0; }
template<class charT, class traits> constexpr bool operator >(
basic_string_view<charT, traits> x, basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) > 0; }
template<class charT, class traits> constexpr bool operator >(
basic_string_view<charT, traits> x,
typename std::decay<basic_string_view<charT, traits>>::type y)
noexcept
{ return x.compare(y) > 0; }
template<class charT, class traits> constexpr bool operator >(
typename std::decay<basic_string_view<charT, traits>>::type x,
basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) > 0; }
template<class charT, class traits> constexpr bool operator <=(
basic_string_view<charT, traits> x, basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) <= 0; }
template<class charT, class traits> constexpr bool operator <=(
basic_string_view<charT, traits> x,
typename std::decay<basic_string_view<charT, traits>>::type y)
noexcept
{ return x.compare(y) <= 0; }
template<class charT, class traits> constexpr bool operator <=(
typename std::decay<basic_string_view<charT, traits>>::type x,
basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) <= 0; }
template<class charT, class traits> constexpr bool operator >=(
basic_string_view<charT, traits> x, basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) >= 0; }
template<class charT, class traits> constexpr bool operator >=(
basic_string_view<charT, traits> x,
typename std::decay<basic_string_view<charT, traits>>::type y)
noexcept
{ return x.compare(y) >= 0; }
template<class charT, class traits> constexpr bool operator >=(
typename std::decay<basic_string_view<charT, traits>>::type x,
basic_string_view<charT, traits> y)
noexcept
{ return x.compare(y) >= 0; }
template<class charT, class traits> std::basic_ostream<charT, traits> &
operator <<(
std::basic_ostream<charT, traits> & os,
basic_string_view<charT, traits> str)
{
typename std::basic_ostream<charT, traits>::sentry sentry;
if (sentry) {
auto const w = os.width();
auto const pad
= std::max<std::make_unsigned<decltype(w + str.size())>::type>(
w < 0 ? 0 : w, str.size());
auto const after = (os.flags() & std::ios_base::adjustfield)
== std::ios_base::left;
if (pad != 0 && !after) {
auto const c = os.fill();
for (; pad != 0; --pad) {
os.rdbuf()->sputc(c);
}
}
os.rdbuf()->sputn(str.data(), str.size());
if (pad != 0 && after) {
auto const c = os.fill();
for (; pad != 0; --pad) {
os.rdbuf()->sputc(c);
}
}
os.width(0);
} else {
os.setstate(std::ios_base::failbit);
}
return os;
}
#if defined _MSC_VER
#pragma warning(pop)
#endif
using string_view = basic_string_view<char>;
using u16string_view = basic_string_view<char16_t>;
using u32string_view = basic_string_view<char32_t>;
using wstring_view = basic_string_view<wchar_t>;
// no literals::string_view_literals::operator "" sv
}
namespace std {
template<> struct hash<o3tl::string_view> {
std::size_t operator ()(o3tl::string_view s)
{ return hash<string>()(string(s.data(), s.size())); }
};
template<> struct hash<o3tl::u16string_view> {
std::size_t operator ()(o3tl::u16string_view s)
{ return hash<u16string>()(u16string(s.data(), s.size())); }
};
template<> struct hash<o3tl::u32string_view> {
std::size_t operator ()(o3tl::u32string_view s)
{ return hash<u32string>()(u32string(s.data(), s.size())); }
};
template<> struct hash<o3tl::wstring_view> {
std::size_t operator ()(o3tl::wstring_view s)
{ return hash<wstring>()(wstring(s.data(), s.size())); }
};
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
......@@ -31,6 +31,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\
o3tl/qa/test-cow_wrapper \
o3tl/qa/test-lru_map \
o3tl/qa/test-sorted_vector \
o3tl/qa/test-string_view \
o3tl/qa/test-typed_flags \
o3tl/qa/test-vector_pool \
))
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sal/config.h>
#include <stdexcept>
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <o3tl/string_view.hxx>
namespace {
class Test: public CppUnit::TestFixture {
private:
CPPUNIT_TEST_SUITE(Test);
CPPUNIT_TEST(testCharLiteral);
CPPUNIT_TEST(testChar16Literal);
CPPUNIT_TEST(testChar32Literal);
CPPUNIT_TEST(testWcharLiteral);
CPPUNIT_TEST(testOperations);
CPPUNIT_TEST_SUITE_END();
void testCharLiteral() {
char * const s1 = const_cast<char *>("foo");
o3tl::string_view v1(s1);
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v1.size());
char const * const s2 = "foo";
o3tl::string_view v2(s2);
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v2.size());
char s3[] = "foo";
o3tl::string_view v3(s3);
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v3.size());
o3tl::string_view v4("foo");
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v4.size());
}
void testChar16Literal() {
char16_t * const s1 = const_cast<char16_t *>(u"foo");
o3tl::u16string_view v1(s1);
CPPUNIT_ASSERT_EQUAL(o3tl::u16string_view::size_type(3), v1.size());
char16_t const * const s2 = u"foo";
o3tl::u16string_view v2(s2);
CPPUNIT_ASSERT_EQUAL(o3tl::u16string_view::size_type(3), v2.size());
char16_t s3[] = u"foo";
o3tl::u16string_view v3(s3);
CPPUNIT_ASSERT_EQUAL(o3tl::u16string_view::size_type(3), v3.size());
o3tl::u16string_view v4(u"foo");
CPPUNIT_ASSERT_EQUAL(o3tl::u16string_view::size_type(3), v4.size());
}
void testChar32Literal() {
char32_t * const s1 = const_cast<char32_t *>(U"foo");
o3tl::u32string_view v1(s1);
CPPUNIT_ASSERT_EQUAL(o3tl::u32string_view::size_type(3), v1.size());
char32_t const * const s2 = U"foo";
o3tl::u32string_view v2(s2);
CPPUNIT_ASSERT_EQUAL(o3tl::u32string_view::size_type(3), v2.size());
char32_t s3[] = U"foo";
o3tl::u32string_view v3(s3);
CPPUNIT_ASSERT_EQUAL(o3tl::u32string_view::size_type(3), v3.size());
o3tl::u32string_view v4(U"foo");
CPPUNIT_ASSERT_EQUAL(o3tl::u32string_view::size_type(3), v4.size());
}
void testWcharLiteral() {
wchar_t * const s1 = const_cast<wchar_t *>(L"foo");
o3tl::wstring_view v1(s1);
CPPUNIT_ASSERT_EQUAL(o3tl::wstring_view::size_type(3), v1.size());
wchar_t const * const s2 = L"foo";
o3tl::wstring_view v2(s2);
CPPUNIT_ASSERT_EQUAL(o3tl::wstring_view::size_type(3), v2.size());
wchar_t s3[] = L"foo";
o3tl::wstring_view v3(s3);
CPPUNIT_ASSERT_EQUAL(o3tl::wstring_view::size_type(3), v3.size());
o3tl::wstring_view v4(L"foo");
CPPUNIT_ASSERT_EQUAL(o3tl::wstring_view::size_type(3), v4.size());
}
void testOperations() {
o3tl::string_view const v("fox");
auto npos = o3tl::string_view::npos;
// o3tl::basic_string_view::npos will be (implicitly) inline with
// C++17, but for now can't be passed as 'const T& expected'
// argument into CppUnit::assertEquals, so take this detour
CPPUNIT_ASSERT_EQUAL('f', *v.begin());
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::difference_type(3), v.end() - v.begin());
CPPUNIT_ASSERT_EQUAL('f', *v.cbegin());
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::difference_type(3), v.cend() - v.cbegin());
CPPUNIT_ASSERT_EQUAL('x', *v.rbegin());
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::difference_type(3), v.rend() - v.rbegin());
CPPUNIT_ASSERT_EQUAL('x', *v.crbegin());
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::difference_type(3), v.crend() - v.crbegin());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v.size());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v.length());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::npos - 1, v.max_size());
CPPUNIT_ASSERT(!v.empty());
CPPUNIT_ASSERT_EQUAL('o', v[1]);
try {
v.at(o3tl::string_view::npos);
CPPUNIT_FAIL("missing exception");
} catch (std::out_of_range &) {}
CPPUNIT_ASSERT_EQUAL('f', v.at(0));
CPPUNIT_ASSERT_EQUAL('x', v.at(2));
try {
v.at(3);
CPPUNIT_FAIL("missing exception");
} catch (std::out_of_range &) {}
CPPUNIT_ASSERT_EQUAL('f', v.front());
CPPUNIT_ASSERT_EQUAL('x', v.back());
CPPUNIT_ASSERT_EQUAL('f', *v.data());
{
o3tl::string_view v1("fox");
v1.remove_prefix(2);
CPPUNIT_ASSERT_EQUAL('x', v1.front());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(1), v1.size());
}
{
o3tl::string_view v1("fox");
v1.remove_suffix(2);
CPPUNIT_ASSERT_EQUAL('f', v1.front());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(1), v1.size());
}
{
o3tl::string_view v1("fox");
o3tl::string_view v2("giraffe");
v1.swap(v2);
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(7), v1.size());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(3), v2.size());
}
{
char a[2];
auto n = v.copy(a, 10, 1);
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(2), n);
CPPUNIT_ASSERT_EQUAL('o', a[0]);
CPPUNIT_ASSERT_EQUAL('x', a[1]);
}
{
auto v1 = v.substr(1);
CPPUNIT_ASSERT_EQUAL('o', v1.front());
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(2), v1.size());
}
CPPUNIT_ASSERT(v.compare(o3tl::string_view("foo")) > 0);
CPPUNIT_ASSERT(v.compare(0, 2, o3tl::string_view("foo")) < 0);
CPPUNIT_ASSERT_EQUAL(
0, v.compare(0, 2, o3tl::string_view("foo"), 0, 2));
CPPUNIT_ASSERT_EQUAL(0, v.compare("fox"));
CPPUNIT_ASSERT(v.compare(1, 2, "abc") > 0);
CPPUNIT_ASSERT_EQUAL(0, v.compare(1, 2, "oxx", 2));
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(1), v.find("ox"));
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(1), v.find('o'));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find("oxx", 0, 2));
CPPUNIT_ASSERT_EQUAL(npos, v.find("oxx"));
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(1), v.rfind("ox"));
CPPUNIT_ASSERT_EQUAL(o3tl::string_view::size_type(1), v.rfind('o'));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1),
v.rfind("oxx", o3tl::string_view::npos, 2));
CPPUNIT_ASSERT_EQUAL(npos, v.rfind("oxx"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_first_of("nop"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_first_of('o'));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_first_of("nofx", 0, 2));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(0), v.find_first_of("nofx"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_last_of("nop"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_last_of('o'));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1),
v.find_last_of("nofx", o3tl::string_view::npos, 2));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(2), v.find_last_of("nofx"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_first_not_of("fx"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_first_not_of('f'));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_first_not_of("fxo", 0, 2));
CPPUNIT_ASSERT_EQUAL(npos, v.find_first_not_of("fxo"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_last_not_of("fx"));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1), v.find_last_not_of('x'));
CPPUNIT_ASSERT_EQUAL(
o3tl::string_view::size_type(1),
v.find_last_not_of("fxo", o3tl::string_view::npos, 2));
CPPUNIT_ASSERT_EQUAL(npos, v.find_last_not_of("fxo"));
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment