Browse Source

Add auxiliary methods for JSONPointer

core_refactor
Anton Tarasenko 2 years ago
parent
commit
09731be8c3
  1. 105
      sources/Text/JSON/JSONPointer.uc

105
sources/Text/JSON/JSONPointer.uc

@ -5,7 +5,7 @@
* Path "/a/b/c" will be stored as a sequence of components "a", "b" and "c",
* path "/" will be stored as a singular empty component ""
* and empty path "" would mean that there is not components at all.
* Copyright 2021 Anton Tarasenko
* Copyright 2021-2023 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
@ -293,6 +293,30 @@ public final function int GetNumericComponent(int index)
return components[index].asNumber;
}
/**
* Checks whether component at given index can be used to index array.
*
* This method accepts numeric components plus component equal to "-", that can
* be used to point at the element after the last on in the `JSONArray`.
*
* @param index Index of the component to check.
* @param `true` if component with given index exists and it either positive
* number or "-".
*/
public final function bool IsComponentArrayApplicable(int index)
{
local bool isAddElementAlias;
local Text component;
if (GetNumericComponent(index) >= 0) {
return true;
}
component = GetComponent(index);
isAddElementAlias = P("-").IsEqual(component);
_.memory.Free(component);
return isAddElementAlias;
}
/**
* Converts caller `JSONPointer` into it's `Text` representation.
*
@ -418,6 +442,85 @@ public final function JSONPointer Copy(
return newPointer;
}
/**
* Appends path, contained in JSON pointer `other` to the caller JSON pointer.
* Appending "/A/B/7/C" to "/object/hey/1/there/" produces
* "/object/hey/1/there//A/B/7/C".
*
* @param other Pointer to append. If `none` - caller `JSONPointer` will
* not change.
* @return Reference to the caller `JSONPointer` to allow for method chaining.
*/
public final function JSONPointer Append(JSONPointer other)
{
local int i;
local array<Component> otherComponents;
if (other == none) {
return self;
}
otherComponents = other.components;
for (i = 0; i < otherComponents.length; i += 1)
{
if (otherComponents[i].asText != none) {
otherComponents[i].asText = otherComponents[i].asText.MutableCopy();
}
components[components.length] = otherComponents[i];
}
return self;
}
/**
* Checks if given pointer corresponds with the beginning of the caller one.
*
* Pointer starts with another one if it includes all of its fields from
* the beginning and in order
* E.g. "/A/B/C" starts with "/A/B", but not with "/A/B/C/D", "/D/A/B/C" or
* "/A/B/CD".
*
* @param other Candidate into being caller pointer's prefix.
* @return `true` if `other` is prefix and `false` otherwise. `none` is
* considered to be an empty pointer and, therefore, prefix to any other
* pointer.
*/
public final function bool StartsWith(JSONPointer other)
{
local int i;
local array<Component> otherComponents;
// `none` is same as empty
if (other == none) return true;
otherComponents = other.components;
// Not enough length
if (components.length < otherComponents.length) return false;
for (i = 0; i < otherComponents.length; i += 1)
{
// Compare numeric components if at least one is such
if ( components[i].testedForBeingNumeric
|| otherComponents[i].testedForBeingNumeric)
{
if (GetNumericComponent(i) != other.GetNumericComponent(i)) {
return false;
}
// End this iteration for numeric component, but continue for
// text ones
if (GetNumericComponent(i) >= 0) {
continue;
}
}
// We can reach here if:
// 1. Neither components have `testedForBeingNumeric` set to
// `true`, neither `asText` fields are `none` by the invariant;
// 2. At least one had `testedForBeingNumeric`, but they tested
// negative for being numeric.
if (!components[i].asText.Compare(otherComponents[i].asText)) {
return false;
}
}
return true;
}
defaultproperties
{
TSLASH = 0

Loading…
Cancel
Save