Address review feedback
Signed-off-by: Nicholas Van Sickle <nvsickle@amazon.com>
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
|
||||
#include <AzCore/DOM/DomPatch.h>
|
||||
#include <AzCore/DOM/DomUtils.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
|
||||
namespace AZ::Dom
|
||||
{
|
||||
@@ -257,7 +257,8 @@ namespace AZ::Dom
|
||||
return AZ::Failure(sourceLoad.TakeError());
|
||||
}
|
||||
|
||||
return AZ::Success(PatchOperation::CopyOperation(Path(destLoad.GetValue().GetString()), Path(sourceLoad.GetValue().GetString())));
|
||||
return AZ::Success(
|
||||
PatchOperation::CopyOperation(Path(destLoad.GetValue().GetString()), Path(sourceLoad.GetValue().GetString())));
|
||||
}
|
||||
else if (op == "move")
|
||||
{
|
||||
@@ -272,7 +273,8 @@ namespace AZ::Dom
|
||||
return AZ::Failure(sourceLoad.TakeError());
|
||||
}
|
||||
|
||||
return AZ::Success(PatchOperation::MoveOperation(Path(destLoad.GetValue().GetString()), Path(sourceLoad.GetValue().GetString())));
|
||||
return AZ::Success(
|
||||
PatchOperation::MoveOperation(Path(destLoad.GetValue().GetString()), Path(sourceLoad.GetValue().GetString())));
|
||||
}
|
||||
else if (op == "test")
|
||||
{
|
||||
@@ -319,8 +321,9 @@ namespace AZ::Dom
|
||||
const Value* existingValue = stateBeforeApplication.FindChild(m_domPath);
|
||||
if (existingValue == nullptr)
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string::format("Unable to invert DOM remove patch, source path not found: %s", m_domPath.ToString().data()));
|
||||
AZStd::string errorMessage = "Unable to invert DOM remove patch, source path not found: ";
|
||||
m_domPath.AppendToString(errorMessage);
|
||||
return AZ::Failure(AZStd::move(errorMessage));
|
||||
}
|
||||
return AZ::Success(PatchOperation::AddOperation(m_domPath, *existingValue));
|
||||
}
|
||||
@@ -330,8 +333,9 @@ namespace AZ::Dom
|
||||
const Value* existingValue = stateBeforeApplication.FindChild(m_domPath);
|
||||
if (existingValue == nullptr)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Unable to invert DOM replace patch, source path not found: %s", m_domPath.ToString().data()));
|
||||
AZStd::string errorMessage = "Unable to invert DOM replace patch, source path not found: ";
|
||||
m_domPath.AppendToString(errorMessage);
|
||||
return AZ::Failure(AZStd::move(errorMessage));
|
||||
}
|
||||
return AZ::Success(PatchOperation::ReplaceOperation(m_domPath, *existingValue));
|
||||
}
|
||||
@@ -341,8 +345,9 @@ namespace AZ::Dom
|
||||
const Value* existingValue = stateBeforeApplication.FindChild(m_domPath);
|
||||
if (existingValue == nullptr)
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string::format("Unable to invert DOM copy patch, source path not found: %s", m_domPath.ToString().data()));
|
||||
AZStd::string errorMessage = "Unable to invert DOM copy patch, source path not found: ";
|
||||
m_domPath.AppendToString(errorMessage);
|
||||
return AZ::Failure(AZStd::move(errorMessage));
|
||||
}
|
||||
return AZ::Success(PatchOperation::ReplaceOperation(m_domPath, *existingValue));
|
||||
}
|
||||
@@ -367,8 +372,9 @@ namespace AZ::Dom
|
||||
const Value* existingValue = stateBeforeApplication.FindChild(commonAncestor);
|
||||
if (existingValue == nullptr)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Unable to invert DOM move patch, common ancestor path not found: %s", commonAncestor.ToString().data()));
|
||||
AZStd::string errorMessage = "Unable to invert DOM copy patch, common ancestor path not found: ";
|
||||
commonAncestor.AppendToString(errorMessage);
|
||||
return AZ::Failure(AZStd::move(errorMessage));
|
||||
}
|
||||
return AZ::Success(PatchOperation::ReplaceOperation(commonAncestor, *existingValue));
|
||||
}
|
||||
@@ -383,10 +389,10 @@ namespace AZ::Dom
|
||||
}
|
||||
|
||||
AZ::Outcome<PatchOperation::PathContext, AZStd::string> PatchOperation::LookupPath(
|
||||
Value& rootElement, const Path& path, AZ::u8 existenceCheckFlags)
|
||||
Value& rootElement, const Path& path, ExistenceCheckFlags flags)
|
||||
{
|
||||
const bool verifyFullPath = existenceCheckFlags & VerifyFullPath;
|
||||
const bool allowEndOfArray = existenceCheckFlags & AllowEndOfArray;
|
||||
const bool verifyFullPath = (flags & ExistenceCheckFlags::VerifyFullPath) != ExistenceCheckFlags::DefaultExistenceCheck;
|
||||
const bool allowEndOfArray = (flags & ExistenceCheckFlags::AllowEndOfArray) != ExistenceCheckFlags::DefaultExistenceCheck;
|
||||
|
||||
Path target = path;
|
||||
if (target.Size() == 0)
|
||||
@@ -414,7 +420,9 @@ namespace AZ::Dom
|
||||
Value* targetValue = rootElement.FindMutableChild(target);
|
||||
if (targetValue == nullptr)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Path not found (%s)", target.ToString().data()));
|
||||
AZStd::string errorMessage = "Path not found: ";
|
||||
target.AppendToString(errorMessage);
|
||||
return AZ::Failure(AZStd::move(errorMessage));
|
||||
}
|
||||
|
||||
if (destinationIndex.IsIndex() || destinationIndex.IsEndOfArray())
|
||||
@@ -450,7 +458,7 @@ namespace AZ::Dom
|
||||
|
||||
PatchOperation::PatchOutcome PatchOperation::ApplyAdd(Value& rootElement) const
|
||||
{
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, AllowEndOfArray);
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, ExistenceCheckFlags::AllowEndOfArray);
|
||||
if (!pathLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(pathLookup.TakeError());
|
||||
@@ -481,7 +489,7 @@ namespace AZ::Dom
|
||||
|
||||
PatchOperation::PatchOutcome PatchOperation::ApplyRemove(Value& rootElement) const
|
||||
{
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, VerifyFullPath | AllowEndOfArray);
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, ExistenceCheckFlags::VerifyFullPath | ExistenceCheckFlags::AllowEndOfArray);
|
||||
if (!pathLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(pathLookup.TakeError());
|
||||
@@ -505,7 +513,7 @@ namespace AZ::Dom
|
||||
|
||||
PatchOperation::PatchOutcome PatchOperation::ApplyReplace(Value& rootElement) const
|
||||
{
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, VerifyFullPath);
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, ExistenceCheckFlags::VerifyFullPath);
|
||||
if (!pathLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(pathLookup.TakeError());
|
||||
@@ -517,13 +525,13 @@ namespace AZ::Dom
|
||||
|
||||
PatchOperation::PatchOutcome PatchOperation::ApplyCopy(Value& rootElement) const
|
||||
{
|
||||
auto sourceLookup = LookupPath(rootElement, GetSourcePath(), VerifyFullPath);
|
||||
auto sourceLookup = LookupPath(rootElement, GetSourcePath(), ExistenceCheckFlags::VerifyFullPath);
|
||||
if (!sourceLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(sourceLookup.TakeError());
|
||||
}
|
||||
|
||||
auto destLookup = LookupPath(rootElement, m_domPath, AllowEndOfArray);
|
||||
auto destLookup = LookupPath(rootElement, m_domPath, ExistenceCheckFlags::AllowEndOfArray);
|
||||
if (!destLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(destLookup.TakeError());
|
||||
@@ -535,13 +543,13 @@ namespace AZ::Dom
|
||||
|
||||
PatchOperation::PatchOutcome PatchOperation::ApplyMove(Value& rootElement) const
|
||||
{
|
||||
auto sourceLookup = LookupPath(rootElement, GetSourcePath(), VerifyFullPath);
|
||||
auto sourceLookup = LookupPath(rootElement, GetSourcePath(), ExistenceCheckFlags::VerifyFullPath);
|
||||
if (!sourceLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(sourceLookup.TakeError());
|
||||
}
|
||||
|
||||
auto destLookup = LookupPath(rootElement, m_domPath, AllowEndOfArray);
|
||||
auto destLookup = LookupPath(rootElement, m_domPath, ExistenceCheckFlags::AllowEndOfArray);
|
||||
if (!destLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(destLookup.TakeError());
|
||||
@@ -568,7 +576,7 @@ namespace AZ::Dom
|
||||
|
||||
PatchOperation::PatchOutcome PatchOperation::ApplyTest(Value& rootElement) const
|
||||
{
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, VerifyFullPath);
|
||||
auto pathLookup = LookupPath(rootElement, m_domPath, ExistenceCheckFlags::VerifyFullPath);
|
||||
if (!pathLookup.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(pathLookup.TakeError());
|
||||
@@ -670,32 +678,32 @@ namespace AZ::Dom
|
||||
return m_operations[index];
|
||||
}
|
||||
|
||||
Patch::OperationsContainer::iterator Patch::begin()
|
||||
auto Patch::begin() -> OperationsContainer::iterator
|
||||
{
|
||||
return m_operations.begin();
|
||||
}
|
||||
|
||||
Patch::OperationsContainer::iterator Patch::end()
|
||||
auto Patch::end() -> OperationsContainer::iterator
|
||||
{
|
||||
return m_operations.end();
|
||||
}
|
||||
|
||||
Patch::OperationsContainer::const_iterator Patch::begin() const
|
||||
auto Patch::begin() const -> OperationsContainer::const_iterator
|
||||
{
|
||||
return m_operations.cbegin();
|
||||
}
|
||||
|
||||
Patch::OperationsContainer::const_iterator Patch::end() const
|
||||
auto Patch::end() const -> OperationsContainer::const_iterator
|
||||
{
|
||||
return m_operations.cend();
|
||||
}
|
||||
|
||||
Patch::OperationsContainer::const_iterator Patch::cbegin() const
|
||||
auto Patch::cbegin() const -> OperationsContainer::const_iterator
|
||||
{
|
||||
return m_operations.cbegin();
|
||||
}
|
||||
|
||||
Patch::OperationsContainer::const_iterator Patch::cend() const
|
||||
auto Patch::cend() const -> OperationsContainer::const_iterator
|
||||
{
|
||||
return m_operations.cend();
|
||||
}
|
||||
@@ -794,7 +802,8 @@ namespace AZ::Dom
|
||||
return PatchOperation(AZStd::move(testPath), PatchOperation::Type::Test, AZStd::move(value));
|
||||
}
|
||||
|
||||
PatchInfo GenerateHierarchicalDeltaPatch(const Value& beforeState, const Value& afterState)
|
||||
PatchInfo GenerateHierarchicalDeltaPatch(
|
||||
const Value& beforeState, const Value& afterState, const DeltaPatchGenerationParameters& params)
|
||||
{
|
||||
PatchInfo patches;
|
||||
|
||||
@@ -804,7 +813,7 @@ namespace AZ::Dom
|
||||
patches.m_inversePatches.PushFront(AZStd::move(inverse));
|
||||
};
|
||||
|
||||
AZStd::function<void(const Path&, const Value&, const Value&)> CompareValues;
|
||||
AZStd::function<void(const Path&, const Value&, const Value&)> compareValues;
|
||||
|
||||
struct PendingComparison
|
||||
{
|
||||
@@ -822,7 +831,7 @@ namespace AZ::Dom
|
||||
AZStd::queue<PendingComparison> entriesToCompare;
|
||||
|
||||
AZStd::unordered_set<AZ::Name::Hash> desiredKeys;
|
||||
auto CompareObjects = [&](const Path& path, const Value& before, const Value& after)
|
||||
auto compareObjects = [&](const Path& path, const Value& before, const Value& after)
|
||||
{
|
||||
desiredKeys.clear();
|
||||
Path subPath = path;
|
||||
@@ -853,22 +862,22 @@ namespace AZ::Dom
|
||||
}
|
||||
};
|
||||
|
||||
auto CompareArrays = [&](const Path& path, const Value& before, const Value& after)
|
||||
auto compareArrays = [&](const Path& path, const Value& before, const Value& after)
|
||||
{
|
||||
const size_t beforeSize = before.ArraySize();
|
||||
const size_t afterSize = after.ArraySize();
|
||||
|
||||
// If more than replaceThreshold values differ, do a replace operation instead
|
||||
constexpr size_t replaceThreshold = 3;
|
||||
size_t changedValueCount = 0;
|
||||
for (size_t i = 0; i < afterSize; ++i)
|
||||
if (params.m_replaceThreshold != DeltaPatchGenerationParameters::NoReplace)
|
||||
{
|
||||
if (i < beforeSize)
|
||||
size_t changedValueCount = 0;
|
||||
const size_t entriesToEnumerate = AZStd::min(beforeSize, afterSize);
|
||||
for (size_t i = 0; i < entriesToEnumerate; ++i)
|
||||
{
|
||||
if (before[i] != after[i])
|
||||
{
|
||||
++changedValueCount;
|
||||
if (changedValueCount >= replaceThreshold)
|
||||
if (changedValueCount >= params.m_replaceThreshold)
|
||||
{
|
||||
AddPatch(PatchOperation::ReplaceOperation(path, after), PatchOperation::ReplaceOperation(path, before));
|
||||
return;
|
||||
@@ -904,7 +913,7 @@ namespace AZ::Dom
|
||||
}
|
||||
};
|
||||
|
||||
auto CompareNodes = [&](const Path& path, const Value& before, const Value& after)
|
||||
auto compareNodes = [&](const Path& path, const Value& before, const Value& after)
|
||||
{
|
||||
if (before.GetNodeName() != after.GetNodeName())
|
||||
{
|
||||
@@ -912,12 +921,12 @@ namespace AZ::Dom
|
||||
}
|
||||
else
|
||||
{
|
||||
CompareObjects(path, before, after);
|
||||
CompareArrays(path, before, after);
|
||||
compareObjects(path, before, after);
|
||||
compareArrays(path, before, after);
|
||||
}
|
||||
};
|
||||
|
||||
CompareValues = [&](const Path& path, const Value& before, const Value& after)
|
||||
compareValues = [&](const Path& path, const Value& before, const Value& after)
|
||||
{
|
||||
if (before.GetType() != after.GetType())
|
||||
{
|
||||
@@ -931,15 +940,15 @@ namespace AZ::Dom
|
||||
}
|
||||
else if (before.IsObject())
|
||||
{
|
||||
CompareObjects(path, before, after);
|
||||
compareObjects(path, before, after);
|
||||
}
|
||||
else if (before.IsArray())
|
||||
{
|
||||
CompareArrays(path, before, after);
|
||||
compareArrays(path, before, after);
|
||||
}
|
||||
else if (before.IsNode())
|
||||
{
|
||||
CompareNodes(path, before, after);
|
||||
compareNodes(path, before, after);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -951,7 +960,7 @@ namespace AZ::Dom
|
||||
while (!entriesToCompare.empty())
|
||||
{
|
||||
PendingComparison& comparison = entriesToCompare.front();
|
||||
CompareValues(comparison.m_path, comparison.m_before, comparison.m_after);
|
||||
compareValues(comparison.m_path, comparison.m_before, comparison.m_after);
|
||||
entriesToCompare.pop();
|
||||
}
|
||||
return patches;
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace AZ::Dom
|
||||
PatchOperation(const PatchOperation&) = default;
|
||||
PatchOperation(PatchOperation&&) = default;
|
||||
|
||||
explicit PatchOperation(Path destinationPath, Type type, Value value);
|
||||
explicit PatchOperation(Path destionationPath, Type type, Path sourcePath);
|
||||
explicit PatchOperation(Path path, Type type);
|
||||
PatchOperation(Path destionationPath, Type type, Value value);
|
||||
PatchOperation(Path destionationPath, Type type, Path sourcePath);
|
||||
PatchOperation(Path path, Type type);
|
||||
|
||||
static PatchOperation AddOperation(Path destinationPath, Value value);
|
||||
static PatchOperation RemoveOperation(Path pathToRemove);
|
||||
@@ -72,6 +72,13 @@ namespace AZ::Dom
|
||||
|
||||
AZ::Outcome<PatchOperation, AZStd::string> GetInverse(Value stateBeforeApplication) const;
|
||||
|
||||
enum class ExistenceCheckFlags : AZ::u8
|
||||
{
|
||||
DefaultExistenceCheck = 0x0,
|
||||
VerifyFullPath = 0x1,
|
||||
AllowEndOfArray = 0x2,
|
||||
};
|
||||
|
||||
private:
|
||||
struct PathContext
|
||||
{
|
||||
@@ -79,12 +86,8 @@ namespace AZ::Dom
|
||||
PathEntry m_key;
|
||||
};
|
||||
|
||||
static constexpr AZ::u8 DefaultExistenceCheck = 0x0;
|
||||
static constexpr AZ::u8 VerifyFullPath = 0x1;
|
||||
static constexpr AZ::u8 AllowEndOfArray = 0x2;
|
||||
|
||||
static AZ::Outcome<PathContext, AZStd::string> LookupPath(
|
||||
Value& rootElement, const Path& path, AZ::u8 existenceCheckFlags = DefaultExistenceCheck);
|
||||
Value& rootElement, const Path& path, ExistenceCheckFlags existenceCheckFlags = ExistenceCheckFlags::DefaultExistenceCheck);
|
||||
|
||||
PatchOutcome ApplyAdd(Value& rootElement) const;
|
||||
PatchOutcome ApplyRemove(Value& rootElement) const;
|
||||
@@ -93,11 +96,13 @@ namespace AZ::Dom
|
||||
PatchOutcome ApplyMove(Value& rootElement) const;
|
||||
PatchOutcome ApplyTest(Value& rootElement) const;
|
||||
|
||||
AZStd::variant<AZStd::monostate, Value, Path> m_value;
|
||||
Path m_domPath;
|
||||
Type m_type;
|
||||
AZStd::variant<AZStd::monostate, Value, Path> m_value;
|
||||
};
|
||||
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(PatchOperation::ExistenceCheckFlags);
|
||||
|
||||
class Patch;
|
||||
|
||||
//! The current state of a Patch application operation.
|
||||
@@ -184,8 +189,18 @@ namespace AZ::Dom
|
||||
Patch m_inversePatches;
|
||||
};
|
||||
|
||||
//! Parameters for GenerateHierarchicalDeltaPatch.
|
||||
struct DeltaPatchGenerationParameters
|
||||
{
|
||||
static constexpr size_t NoReplace = AZStd::numeric_limits<size_t>::max();
|
||||
|
||||
//! The threshold of changed values in a node or array which, if exceeded, will cause the generation to create an
|
||||
//! entire "replace" oepration instead. If set to NoReplace, no replacement will occur.
|
||||
size_t m_replaceThreshold = 3;
|
||||
};
|
||||
|
||||
//! Generates a set of patches such that m_forwardPatches.Apply(beforeState) shall produce a document equivalent to afterState, and
|
||||
//! a subsequent m_inversePatches.Apply(beforeState) shall produce the original document. This patch generation strategy does a
|
||||
//! hierarchical comparison and is not guaranteed to create the minimal set of patches required to transform between the two states.
|
||||
PatchInfo GenerateHierarchicalDeltaPatch(const Value& beforeState, const Value& afterState);
|
||||
PatchInfo GenerateHierarchicalDeltaPatch(const Value& beforeState, const Value& afterState, const DeltaPatchGenerationParameters& params = {});
|
||||
} // namespace AZ::Dom
|
||||
|
||||
@@ -54,19 +54,19 @@ namespace AZ::Dom
|
||||
bool PathEntry::operator==(size_t value) const
|
||||
{
|
||||
const size_t* internalValue = AZStd::get_if<size_t>(&m_value);
|
||||
return internalValue == nullptr ? false : (*internalValue) == value;
|
||||
return internalValue != nullptr && *internalValue == value;
|
||||
}
|
||||
|
||||
bool PathEntry::operator==(const AZ::Name& key) const
|
||||
{
|
||||
const AZ::Name* internalValue = AZStd::get_if<AZ::Name>(&m_value);
|
||||
return internalValue == nullptr ? false : (*internalValue) == key;
|
||||
return internalValue != nullptr && *internalValue == key;
|
||||
}
|
||||
|
||||
bool PathEntry::operator==(AZStd::string_view key) const
|
||||
{
|
||||
const AZ::Name* internalValue = AZStd::get_if<AZ::Name>(&m_value);
|
||||
return internalValue == nullptr ? false : (*internalValue) == AZ::Name(key);
|
||||
return internalValue != nullptr && *internalValue == AZ::Name(key);
|
||||
}
|
||||
|
||||
bool PathEntry::operator!=(const PathEntry& other) const
|
||||
@@ -323,13 +323,13 @@ namespace AZ::Dom
|
||||
return size;
|
||||
}
|
||||
|
||||
void Path::FormatString(char* stringBuffer, size_t bufferSize) const
|
||||
size_t Path::FormatString(char* stringBuffer, size_t bufferSize) const
|
||||
{
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
auto putChar = [&](char c)
|
||||
{
|
||||
if (bufferIndex == bufferSize)
|
||||
if (bufferIndex >= bufferSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -360,6 +360,11 @@ namespace AZ::Dom
|
||||
|
||||
for (const PathEntry& entry : m_entries)
|
||||
{
|
||||
if (bufferIndex >= bufferSize)
|
||||
{
|
||||
return bufferIndex;
|
||||
}
|
||||
|
||||
putChar(PathSeparator);
|
||||
if (entry.IsEndOfArray())
|
||||
{
|
||||
@@ -375,7 +380,10 @@ namespace AZ::Dom
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytesWritten = bufferIndex;
|
||||
putChar('\0');
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
AZStd::string Path::ToString() const
|
||||
|
||||
@@ -128,10 +128,19 @@ namespace AZ::Dom
|
||||
size_t GetStringLength() const;
|
||||
//! Formats a JSON-pointer style path string into the target buffer.
|
||||
//! This operation will fail if bufferSize < GetStringLength() + 1
|
||||
void FormatString(char* stringBuffer, size_t bufferSize) const;
|
||||
//! \return The number of bytes written, excepting the null terminator.
|
||||
size_t FormatString(char* stringBuffer, size_t bufferSize) const;
|
||||
//! Returns a JSON-pointer style path string for this path.
|
||||
AZStd::string ToString() const;
|
||||
|
||||
void AppendToString(AZStd::string& output) const;
|
||||
template <class T>
|
||||
void AppendToString(T& output) const
|
||||
{
|
||||
const size_t startIndex = output.length();
|
||||
output.resize_no_construct(startIndex + FormatString(output.data() + startIndex, output.capacity() - startIndex));
|
||||
}
|
||||
|
||||
//! Reads a JSON-pointer style path from pathString and replaces this path's contents.
|
||||
//! Paths are accepted in the following forms:
|
||||
//! "/path/to/foo/0"
|
||||
|
||||
@@ -96,4 +96,25 @@ namespace AZ::Dom::Benchmark
|
||||
state.SetItemsProcessed(3 * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPathEntry_IsEndOfArray);
|
||||
|
||||
BENCHMARK_DEFINE_F(DomPathBenchmark, DomPathEntry_Comparison)(benchmark::State& state)
|
||||
{
|
||||
PathEntry name("name");
|
||||
PathEntry index(0);
|
||||
PathEntry endOfArray;
|
||||
endOfArray.SetEndOfArray();
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
name == name;
|
||||
name == index;
|
||||
name == endOfArray;
|
||||
index == index;
|
||||
index == endOfArray;
|
||||
endOfArray == endOfArray;
|
||||
}
|
||||
|
||||
state.SetItemsProcessed(6 * state.iterations());
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DomPathBenchmark, DomPathEntry_Comparison);
|
||||
}
|
||||
|
||||
@@ -174,4 +174,23 @@ namespace AZ::Dom::Tests
|
||||
p.AppendToString(s);
|
||||
EXPECT_EQ(s, "/foo/0/foo/0");
|
||||
}
|
||||
|
||||
TEST_F(DomPathTests, MixedPath_AppendToFixedString)
|
||||
{
|
||||
Path p("/foo/0");
|
||||
|
||||
{
|
||||
AZStd::fixed_string<7> s;
|
||||
p.AppendToString(s);
|
||||
EXPECT_EQ(s, "/foo/0");
|
||||
}
|
||||
|
||||
{
|
||||
AZStd::fixed_string<9> s;
|
||||
p.AppendToString(s);
|
||||
EXPECT_EQ(s, "/foo/0");
|
||||
p.AppendToString(s);
|
||||
EXPECT_EQ(s, "/foo/0/fo");
|
||||
}
|
||||
}
|
||||
} // namespace AZ::Dom::Tests
|
||||
|
||||
Reference in New Issue
Block a user