Make DOMString a regular nsAutoTString with some special methods for performance in some hot getters. For that, we need to change a bit nsTString: * Support for unowned buffers: Owned buffers now are represented by STRINGBUFFER|OWNED flags, rather than REFCOUNTED. * Inlining of the destructor: It showed up in profiles, it's also just a few instructions, so probably worth it. We could OOL the owned path I guess, if we wanted to. * Inlinling and reordering of NonVoidStringToJsval. Old code had special DOMString path inline with [buffer, literal, copy] paths, then out of line code with [literal, buffer, copy]. Instead, consolidate everything in a [buffer, literal, copy] inline path. Do the same for UTF8/Latin1 strings too for consistency. Differential Revision: https://phabricator.services.mozilla.com/D288148
260 lines
6.3 KiB
C++
260 lines
6.3 KiB
C++
/* 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 "nsASCIIMask.h"
|
|
#include "nsString.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsCRTGlue.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace TestMoveString {
|
|
|
|
#define NEW_VAL "**new value**"
|
|
#define OLD_VAL "old value"
|
|
|
|
typedef mozilla::detail::StringDataFlags Df;
|
|
|
|
static void SetAsOwned(nsACString& aStr, const char* aValue) {
|
|
size_t len = strlen(aValue);
|
|
char* data = new char[len + 1];
|
|
memcpy(data, aValue, len + 1);
|
|
aStr.Adopt(data, len);
|
|
EXPECT_EQ(aStr.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
EXPECT_STREQ(PromiseFlatCString(aStr).get(), aValue);
|
|
}
|
|
|
|
static void ExpectTruncated(const nsACString& aStr) {
|
|
EXPECT_EQ(aStr.Length(), uint32_t(0));
|
|
EXPECT_STREQ(PromiseFlatCString(aStr).get(), "");
|
|
EXPECT_EQ(aStr.GetDataFlags(), Df::TERMINATED);
|
|
}
|
|
|
|
static void ExpectNew(const nsACString& aStr) {
|
|
EXPECT_EQ(aStr.Length(), strlen(NEW_VAL));
|
|
EXPECT_TRUE(aStr.EqualsASCII(NEW_VAL));
|
|
}
|
|
|
|
TEST(MoveString, SharedIntoOwned)
|
|
{
|
|
nsCString out;
|
|
SetAsOwned(out, OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
|
|
nsCString in;
|
|
in.Assign(NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::STRINGBUFFER | Df::OWNED | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::STRINGBUFFER | Df::OWNED | Df::TERMINATED);
|
|
EXPECT_EQ(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, OwnedIntoOwned)
|
|
{
|
|
nsCString out;
|
|
SetAsOwned(out, OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
|
|
nsCString in;
|
|
SetAsOwned(in, NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
EXPECT_EQ(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, LiteralIntoOwned)
|
|
{
|
|
nsCString out;
|
|
SetAsOwned(out, OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
|
|
nsCString in;
|
|
in.AssignLiteral(NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
|
|
EXPECT_EQ(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, AutoIntoOwned)
|
|
{
|
|
nsCString out;
|
|
SetAsOwned(out, OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
|
|
nsAutoCString in;
|
|
in.Assign(NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::STRINGBUFFER | Df::OWNED | Df::TERMINATED);
|
|
EXPECT_NE(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, DepIntoOwned)
|
|
{
|
|
nsCString out;
|
|
SetAsOwned(out, OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
|
|
nsDependentCSubstring in(NEW_VAL "garbage after", strlen(NEW_VAL));
|
|
EXPECT_EQ(in.GetDataFlags(), Df(0));
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::STRINGBUFFER | Df::OWNED | Df::TERMINATED);
|
|
}
|
|
|
|
TEST(MoveString, VoidIntoOwned)
|
|
{
|
|
nsCString out;
|
|
SetAsOwned(out, OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
|
|
nsCString in = VoidCString();
|
|
EXPECT_EQ(in.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
|
|
EXPECT_EQ(out.Length(), 0u);
|
|
EXPECT_STREQ(out.get(), "");
|
|
EXPECT_EQ(out.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
|
|
}
|
|
|
|
TEST(MoveString, SharedIntoAuto)
|
|
{
|
|
nsAutoCString out;
|
|
out.Assign(OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
|
|
nsCString in;
|
|
in.Assign(NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::STRINGBUFFER | Df::OWNED | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::STRINGBUFFER | Df::OWNED | Df::TERMINATED);
|
|
EXPECT_EQ(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, OwnedIntoAuto)
|
|
{
|
|
nsAutoCString out;
|
|
out.Assign(OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
|
|
nsCString in;
|
|
SetAsOwned(in, NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::OWNED | Df::TERMINATED);
|
|
EXPECT_EQ(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, LiteralIntoAuto)
|
|
{
|
|
nsAutoCString out;
|
|
out.Assign(OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
|
|
nsCString in;
|
|
in.AssignLiteral(NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::LITERAL | Df::TERMINATED);
|
|
EXPECT_EQ(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, AutoIntoAuto)
|
|
{
|
|
nsAutoCString out;
|
|
out.Assign(OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
|
|
nsAutoCString in;
|
|
in.Assign(NEW_VAL);
|
|
EXPECT_EQ(in.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
const char* data = in.get();
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
EXPECT_NE(out.get(), data);
|
|
}
|
|
|
|
TEST(MoveString, DepIntoAuto)
|
|
{
|
|
nsAutoCString out;
|
|
out.Assign(OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
|
|
nsDependentCSubstring in(NEW_VAL "garbage after", strlen(NEW_VAL));
|
|
EXPECT_EQ(in.GetDataFlags(), Df(0));
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
ExpectNew(out);
|
|
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
}
|
|
|
|
TEST(MoveString, VoidIntoAuto)
|
|
{
|
|
nsAutoCString out;
|
|
out.Assign(OLD_VAL);
|
|
EXPECT_EQ(out.GetDataFlags(), Df::INLINE | Df::TERMINATED);
|
|
|
|
nsCString in = VoidCString();
|
|
EXPECT_EQ(in.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
|
|
|
|
out.Assign(std::move(in));
|
|
ExpectTruncated(in);
|
|
|
|
EXPECT_EQ(out.Length(), 0u);
|
|
EXPECT_STREQ(out.get(), "");
|
|
EXPECT_EQ(out.GetDataFlags(), Df::VOIDED | Df::TERMINATED);
|
|
}
|
|
|
|
#undef NEW_VAL
|
|
#undef OLD_VAL
|
|
|
|
} // namespace TestMoveString
|