Add Dom::Path class for representing positions in a Dom (#7008)
* Add Dom::Path class for representing positions in a Dom This also adds Value support for doing a path-based lookup. The serialized representation is presently compliant with the JSON-pointer spec but the implementation supports Node types and may be later expanded if we require additional functionality (e.g. XPath style conditional querying). Signed-off-by: Nicholas Van Sickle <nvsickle@amazon.com>
This commit is contained in:
committed by
GitHub
parent
858a92f394
commit
32e2ba754b
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Tests/DOM/DomFixtures.h>
|
||||
#include <AzCore/DOM/DomPath.h>
|
||||
|
||||
namespace AZ::Dom::Benchmark
|
||||
{
|
||||
using DomPathBenchmark = Tests::DomBenchmarkFixture;
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_Concatenate_InPlace)(benchmark::State& state)
|
||||
{
|
||||
AZ::Name entry1("entry1");
|
||||
AZ::Name entry2("entry2");
|
||||
PathEntry end;
|
||||
end.SetEndOfArray();
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
Path p;
|
||||
p /= entry1;
|
||||
p /= entry2;
|
||||
p /= 0;
|
||||
p /= end;
|
||||
}
|
||||
|
||||
state.SetItemsProcessed(4 * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_Concatenate_InPlace);
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_Concatenate_Copy)(benchmark::State& state)
|
||||
{
|
||||
AZ::Name entry1("entry1");
|
||||
AZ::Name entry2("entry2");
|
||||
PathEntry end;
|
||||
end.SetEndOfArray();
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
Path p = Path() / entry1 / entry2 / 0 / end;
|
||||
}
|
||||
|
||||
state.SetItemsProcessed(4 * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_Concatenate_Copy);
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_ToString)(benchmark::State& state)
|
||||
{
|
||||
Path p("/path/with/multiple/0/different/components/65536/999/-");
|
||||
AZStd::string s;
|
||||
s.resize_no_construct(p.GetStringLength());
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
p.GetStringLength();
|
||||
p.FormatString(s.data(), s.size());
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(s.size() * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_ToString);
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_FromString)(benchmark::State& state)
|
||||
{
|
||||
AZStd::string pathString = "/path/with/multiple/0/different/components/including-long-strings-like-this/65536/999/-";
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
Path p(pathString);
|
||||
benchmark::DoNotOptimize(p);
|
||||
}
|
||||
|
||||
state.SetBytesProcessed(pathString.size() * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_FromString);
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPathBenchmark, DomPathEntry_IsEndOfArray)(benchmark::State& state)
|
||||
{
|
||||
PathEntry name("name");
|
||||
PathEntry index(0);
|
||||
PathEntry endOfArray;
|
||||
endOfArray.SetEndOfArray();
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
name.IsEndOfArray();
|
||||
index.IsEndOfArray();
|
||||
endOfArray.IsEndOfArray();
|
||||
}
|
||||
|
||||
state.SetItemsProcessed(3 * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPathEntry_IsEndOfArray);
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/DOM/DomPath.h>
|
||||
#include <AzCore/Name/NameDictionary.h>
|
||||
#include <Tests/DOM/DomFixtures.h>
|
||||
|
||||
namespace AZ::Dom::Tests
|
||||
{
|
||||
class DomPathTests : public DomTestFixture
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(DomPathTests, EmptyPath_IsEmpty)
|
||||
{
|
||||
Path path("");
|
||||
EXPECT_EQ(path.GetEntries().size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, EmptyPath_IsEqualToDefault)
|
||||
{
|
||||
EXPECT_EQ(Path(""), Path());
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, Index_IsNumeric)
|
||||
{
|
||||
EXPECT_EQ(Path("/0")[0], 0);
|
||||
EXPECT_EQ(Path("/20")[0], 20);
|
||||
EXPECT_EQ(Path("/9999")[0], 9999);
|
||||
EXPECT_EQ(Path("/0/4/5/1")[3], 1);
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, Index_ConvertsToString)
|
||||
{
|
||||
Path p;
|
||||
EXPECT_EQ(p.ToString(), "");
|
||||
|
||||
p.Push(0);
|
||||
EXPECT_EQ(p.ToString(), "/0");
|
||||
|
||||
p.Push(1);
|
||||
EXPECT_EQ(p.ToString(), "/0/1");
|
||||
|
||||
p.Push(10);
|
||||
EXPECT_EQ(p.ToString(), "/0/1/10");
|
||||
|
||||
p.Push(9999);
|
||||
EXPECT_EQ(p.ToString(), "/0/1/10/9999");
|
||||
|
||||
p.Pop();
|
||||
EXPECT_EQ(p.ToString(), "/0/1/10");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, Key_IsString)
|
||||
{
|
||||
EXPECT_EQ(Path("/foo")[0], "foo");
|
||||
EXPECT_EQ(Path("/bar")[0], "bar");
|
||||
EXPECT_EQ(Path("/foo/bar/baz12345")[0], "foo");
|
||||
EXPECT_EQ(Path("/foo/bar/baz12345")[2], "baz12345");
|
||||
EXPECT_EQ(Path("//foo")[0], "");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, Key_ConvertsToString)
|
||||
{
|
||||
Path p;
|
||||
|
||||
p.Push("foo");
|
||||
EXPECT_EQ(p.ToString(), "/foo");
|
||||
|
||||
p.Push("bar");
|
||||
EXPECT_EQ(p.ToString(), "/foo/bar");
|
||||
|
||||
p.Push("another_key");
|
||||
EXPECT_EQ(p.ToString(), "/foo/bar/another_key");
|
||||
|
||||
p.Pop();
|
||||
EXPECT_EQ(p.ToString(), "/foo/bar");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, Key_ConvertsFromEscaped)
|
||||
{
|
||||
EXPECT_EQ(Path("/foo~0")[0], "foo~");
|
||||
EXPECT_EQ(Path("/foo~0bar~0~0")[0], "foo~bar~~");
|
||||
EXPECT_EQ(Path("/foo~1bar/baz")[0], "foo/bar");
|
||||
EXPECT_EQ(Path("/~1foo~1")[0], "/foo/");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, Key_ConvertsToEscaped)
|
||||
{
|
||||
Path p;
|
||||
|
||||
p.Push("with~tilde");
|
||||
EXPECT_EQ(p.ToString(), "/with~0tilde");
|
||||
|
||||
p.Push("with/slash");
|
||||
EXPECT_EQ(p.ToString(), "/with~0tilde/with~1slash");
|
||||
|
||||
p.Clear();
|
||||
p.Push("/~with/mixed/characters~");
|
||||
EXPECT_EQ(p.ToString(), "/~1~0with~1mixed~1characters~0");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, MixedPath_Resolves)
|
||||
{
|
||||
EXPECT_EQ(Path("/foo/0")[0], "foo");
|
||||
EXPECT_EQ(Path("/foo/0")[1], 0);
|
||||
EXPECT_EQ(Path("/42/foo/bar/0")[0], 42);
|
||||
EXPECT_EQ(Path("/42/foo/bar/0")[1], "foo");
|
||||
EXPECT_EQ(Path("/42/foo/bar/0")[2], "bar");
|
||||
EXPECT_EQ(Path("/42/foo/bar/0")[3], 0);
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, MixedPath_ConvertsToString)
|
||||
{
|
||||
Path p;
|
||||
|
||||
p.Push("foo");
|
||||
EXPECT_EQ(p.ToString(), "/foo");
|
||||
|
||||
p.Push(0);
|
||||
EXPECT_EQ(p.ToString(), "/foo/0");
|
||||
|
||||
p.Push("another_key");
|
||||
EXPECT_EQ(p.ToString(), "/foo/0/another_key");
|
||||
|
||||
p.Push(100);
|
||||
EXPECT_EQ(p.ToString(), "/foo/0/another_key/100");
|
||||
|
||||
p.Pop();
|
||||
EXPECT_EQ(p.ToString(), "/foo/0/another_key");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, OperatorOverloads_Append)
|
||||
{
|
||||
EXPECT_EQ(Path("/foo/bar"), Path("/foo") / Path("/bar"));
|
||||
EXPECT_EQ(Path("/foo"), Path("/foo") / Path());
|
||||
EXPECT_EQ(Path("/foo/1/bar/0"), Path("/foo/1") / Path("/bar/0"));
|
||||
EXPECT_EQ(Path("/foo") / 0, Path("/foo/0"));
|
||||
EXPECT_EQ(Path() / "foo" / "bar", Path("/foo/bar"));
|
||||
EXPECT_EQ(Path("/foo") / "bar" / "baz", Path("/foo/bar/baz"));
|
||||
|
||||
Path p("/foo/bar");
|
||||
p /= "baz";
|
||||
EXPECT_EQ(p, Path("/foo/bar/baz"));
|
||||
p /= Path("0/1");
|
||||
EXPECT_EQ(p, Path("/foo/bar/baz/0/1"));
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, EndOfArray_FromString)
|
||||
{
|
||||
EXPECT_FALSE(Path("/foo/-")[0].IsEndOfArray());
|
||||
EXPECT_TRUE(Path("/foo/-")[1].IsEndOfArray());
|
||||
EXPECT_TRUE(Path("/foo/-/-")[2].IsEndOfArray());
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, EndOfArray_ToString)
|
||||
{
|
||||
EXPECT_EQ(Path("/-").ToString(), "/-");
|
||||
EXPECT_EQ(Path("/0/-").ToString(), "/0/-");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, MixedPath_AppendToString)
|
||||
{
|
||||
Path p("/foo/0");
|
||||
AZStd::string s;
|
||||
|
||||
p.AppendToString(s);
|
||||
EXPECT_EQ(s, "/foo/0");
|
||||
p.AppendToString(s);
|
||||
EXPECT_EQ(s, "/foo/0/foo/0");
|
||||
}
|
||||
} // namespace AZ::Dom::Tests
|
||||
@@ -219,6 +219,8 @@ set(FILES
|
||||
DOM/DomFixtures.h
|
||||
DOM/DomJsonTests.cpp
|
||||
DOM/DomJsonBenchmarks.cpp
|
||||
DOM/DomPathTests.cpp
|
||||
DOM/DomPathBenchmarks.cpp
|
||||
DOM/DomValueTests.cpp
|
||||
DOM/DomValueBenchmarks.cpp
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user