Added various node manipulation functions so e.g. new elements
can be added to collections before emitting. The code is somewhat ugly, might be revised later.
This commit is contained in:
parent
b0f2ce201a
commit
967fe8c48b
483
dyaml/node.d
483
dyaml/node.d
|
@ -5,7 +5,8 @@
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node of a YAML document. Used to read YAML data once it's loaded.
|
* Node of a YAML document. Used to read YAML data once it's loaded,
|
||||||
|
* and to prepare data to emit.
|
||||||
*/
|
*/
|
||||||
module dyaml.node;
|
module dyaml.node;
|
||||||
|
|
||||||
|
@ -109,6 +110,15 @@ struct Node
|
||||||
Node value;
|
Node value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
///Construct a Pair from two values. Will be converted to Nodes if needed.
|
||||||
|
this(K, V)(K key, V value)
|
||||||
|
{
|
||||||
|
static if(is(K == Node)){this.key = key;}
|
||||||
|
else {this.key = Node(key);}
|
||||||
|
static if(is(V == Node)){this.value = value;}
|
||||||
|
else {this.value = Node(value);}
|
||||||
|
}
|
||||||
|
|
||||||
///Equality test with another Pair.
|
///Equality test with another Pair.
|
||||||
bool equals(ref Pair rhs)
|
bool equals(ref Pair rhs)
|
||||||
{
|
{
|
||||||
|
@ -160,37 +170,34 @@ struct Node
|
||||||
* what Representer determines. Can be used when a
|
* what Representer determines. Can be used when a
|
||||||
* single D data type needs to use multiple YAML tags.
|
* single D data type needs to use multiple YAML tags.
|
||||||
*/
|
*/
|
||||||
this(T)(T value, string tag = null) if (!isArray!T && !isAssociativeArray!T)
|
this(T)(T value, in string tag = null) if (isSomeString!T ||
|
||||||
|
(!isArray!T && !isAssociativeArray!T))
|
||||||
{
|
{
|
||||||
tag_ = Tag(tag);
|
tag_ = Tag(tag);
|
||||||
|
|
||||||
//No copyconstruction.
|
//No copyconstruction.
|
||||||
static if(is(T == Node))
|
static assert(!is(T == Node));
|
||||||
{
|
|
||||||
static assert(false);
|
|
||||||
}
|
|
||||||
//We can easily convert ints, floats, strings.
|
//We can easily convert ints, floats, strings.
|
||||||
else static if(isIntegral!T)
|
static if(isIntegral!T) {value_ = Value(cast(long) value);}
|
||||||
{
|
else static if(isFloatingPoint!T){value_ = Value(cast(real) value);}
|
||||||
value_ = Value(cast(long) value);
|
else static if(isSomeString!T) {value_ = Value(to!string(value));}
|
||||||
}
|
//Other directly supported type.
|
||||||
else static if(isFloatingPoint!T)
|
else static if(Value.allowed!T) {value_ = Value(value);}
|
||||||
{
|
|
||||||
value_ = Value(cast(real) value);
|
|
||||||
}
|
|
||||||
else static if(isSomeString!T)
|
|
||||||
{
|
|
||||||
value_ = Value(to!string(value));
|
|
||||||
}
|
|
||||||
//Directly supported type.
|
|
||||||
else static if(Value.allowed!T)
|
|
||||||
{
|
|
||||||
value_ = Value(value);
|
|
||||||
}
|
|
||||||
//User defined type.
|
//User defined type.
|
||||||
else
|
else {value_ = userValue(value);}
|
||||||
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node(42))
|
||||||
{
|
{
|
||||||
value_ = userValue(value);
|
assert(isScalar() && !isSequence && !isMapping && !isUserType);
|
||||||
|
assert(get!int == 42 && get!float == 42.0f && get!string == "42");
|
||||||
|
assert(!isUserType());
|
||||||
|
}
|
||||||
|
with(Node(new class{int a = 5;}))
|
||||||
|
{
|
||||||
|
assert(isUserType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +218,7 @@ struct Node
|
||||||
* which both are internally represented as an array_
|
* which both are internally represented as an array_
|
||||||
* of nodes.
|
* of nodes.
|
||||||
*/
|
*/
|
||||||
this(T)(T[] array, string tag = null)
|
this(T)(T[] array, in string tag = null) if (!isSomeString!(T[]))
|
||||||
{
|
{
|
||||||
tag_ = Tag(tag);
|
tag_ = Tag(tag);
|
||||||
|
|
||||||
|
@ -222,13 +229,19 @@ struct Node
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Node[] nodes;
|
Node[] nodes;
|
||||||
foreach(ref value; array)
|
foreach(ref value; array){nodes ~= Node(value);}
|
||||||
{
|
|
||||||
nodes ~= Node(value);
|
|
||||||
}
|
|
||||||
value_ = Value(nodes);
|
value_ = Value(nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node([1, 2, 3]))
|
||||||
|
{
|
||||||
|
assert(!isScalar() && isSequence && !isMapping && !isUserType);
|
||||||
|
assert(length == 3);
|
||||||
|
assert(opIndex(2).get!int == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a node from an associative array_.
|
* Construct a node from an associative array_.
|
||||||
|
@ -246,24 +259,26 @@ struct Node
|
||||||
* (!!omap) and pairs (!!pairs), which are all
|
* (!!omap) and pairs (!!pairs), which are all
|
||||||
* internally represented as an array_ of node pairs.
|
* internally represented as an array_ of node pairs.
|
||||||
*/
|
*/
|
||||||
this(K, V)(V[K] array, string tag = null)
|
this(K, V)(V[K] array, in string tag = null)
|
||||||
{
|
{
|
||||||
tag_ = Tag(tag);
|
tag_ = Tag(tag);
|
||||||
|
|
||||||
Node.Pair[] pairs;
|
Node.Pair[] pairs;
|
||||||
|
foreach(ref key, ref value; array){pairs ~= Pair(key, value);}
|
||||||
Node.Pair pair;
|
|
||||||
foreach(ref key, ref value; array)
|
|
||||||
{
|
|
||||||
static if(is(K == Node)){pair.key = key;}
|
|
||||||
else{pair.key = Node(key);}
|
|
||||||
static if(is(V == Node)){pair.value = value;}
|
|
||||||
else{pair.value = Node(value);}
|
|
||||||
pairs ~= pair;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_ = Value(pairs);
|
value_ = Value(pairs);
|
||||||
}
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
int[string] aa;
|
||||||
|
aa["1"] = 1;
|
||||||
|
aa["2"] = 2;
|
||||||
|
with(Node(aa))
|
||||||
|
{
|
||||||
|
assert(!isScalar() && !isSequence && isMapping && !isUserType);
|
||||||
|
assert(length == 2);
|
||||||
|
assert(opIndex("2").get!int == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a node from arrays of keys_ and values_.
|
* Construct a node from arrays of keys_ and values_.
|
||||||
|
@ -288,7 +303,7 @@ struct Node
|
||||||
* (!!omap) and pairs (!!pairs), which are all
|
* (!!omap) and pairs (!!pairs), which are all
|
||||||
* internally represented as an array_ of node pairs.
|
* internally represented as an array_ of node pairs.
|
||||||
*/
|
*/
|
||||||
this(K, V)(K[] keys, V[] values, string tag = null)
|
this(K, V)(K[] keys, V[] values, in string tag = null)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(keys.length == values.length,
|
assert(keys.length == values.length,
|
||||||
|
@ -300,19 +315,18 @@ struct Node
|
||||||
tag_ = Tag(tag);
|
tag_ = Tag(tag);
|
||||||
|
|
||||||
Node.Pair[] pairs;
|
Node.Pair[] pairs;
|
||||||
|
foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);}
|
||||||
Node.Pair pair;
|
|
||||||
foreach(i; 0 .. keys.length)
|
|
||||||
{
|
|
||||||
static if(is(K == Node)){pair.key = keys[i];}
|
|
||||||
else{pair.key = Node(keys[i]);}
|
|
||||||
static if(is(V == Node)){pair.value = values[i];}
|
|
||||||
else{pair.value = Node(values[i]);}
|
|
||||||
pairs ~= pair;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_ = Value(pairs);
|
value_ = Value(pairs);
|
||||||
}
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node(["1", "2"], [1, 2]))
|
||||||
|
{
|
||||||
|
assert(!isScalar() && !isSequence && isMapping && !isUserType);
|
||||||
|
assert(length == 2);
|
||||||
|
assert(opIndex("2").get!int == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///Is this node valid (initialized)?
|
///Is this node valid (initialized)?
|
||||||
@property bool isValid() const {return value_.hasValue;}
|
@property bool isValid() const {return value_.hasValue;}
|
||||||
|
@ -509,47 +523,23 @@ struct Node
|
||||||
*
|
*
|
||||||
* Returns: Value corresponding to the index.
|
* Returns: Value corresponding to the index.
|
||||||
*
|
*
|
||||||
* Throws: NodeException if the index could not be found.
|
* Throws: NodeException if the index could not be found,
|
||||||
|
* non-integral index is used with a sequence or the node is
|
||||||
|
* not a collection.
|
||||||
*/
|
*/
|
||||||
Node opIndex(T)(in T index)
|
Node opIndex(T)(T index)
|
||||||
{
|
{
|
||||||
if(isSequence)
|
if(isSequence)
|
||||||
{
|
{
|
||||||
//Sequence, index must be integral.
|
checkSequenceIndex(index);
|
||||||
static if(isIntegral!T)
|
static if(isIntegral!T){return value_.get!(Node[])[index];}
|
||||||
{
|
assert(false);
|
||||||
auto nodes = value_.get!(Node[]);
|
|
||||||
enforce(index >= 0 && index < nodes.length,
|
|
||||||
new NodeException("Index to a sequence out of range: "
|
|
||||||
~ to!string(index), startMark_));
|
|
||||||
return nodes[index];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NodeException("Indexing a sequence with a non-integer type.",
|
|
||||||
startMark_);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(isMapping)
|
else if(isMapping)
|
||||||
{
|
{
|
||||||
//Mapping, look for keys convertible to T with value of index.
|
auto idx = findPair(index);
|
||||||
foreach(ref pair; get!(Pair[]))
|
if(idx >= 0){return get!(Pair[])[idx].value;}
|
||||||
{
|
|
||||||
//Handle NaN.
|
|
||||||
static if(isFloatingPoint!T)
|
|
||||||
{
|
|
||||||
if(isFloat && isNaN(index) && isNaN(pair.key.get!real))
|
|
||||||
{
|
|
||||||
return pair.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//If we can get the key as type T, get it and compare to
|
|
||||||
//index, and return value if the key matches.
|
|
||||||
if(pair.key.convertsTo!T && pair.key.get!T == index)
|
|
||||||
{
|
|
||||||
return pair.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new NodeException("Mapping index not found" ~
|
throw new NodeException("Mapping index not found" ~
|
||||||
isSomeString!T ? ": " ~ to!string(index) : "",
|
isSomeString!T ? ": " ~ to!string(index) : "",
|
||||||
startMark_);
|
startMark_);
|
||||||
|
@ -586,6 +576,77 @@ struct Node
|
||||||
assert(null !is collectException(nmap["42"]));
|
assert(null !is collectException(nmap["42"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set element at the specified index of a collection.
|
||||||
|
*
|
||||||
|
* This method can only be called on collection nodes.
|
||||||
|
*
|
||||||
|
* If the node is a sequence, index must be integral.
|
||||||
|
*
|
||||||
|
* If the node is a mapping, set the value_ corresponding to the first
|
||||||
|
* key matching index (including conversion, so e.g. "42" matches 42).
|
||||||
|
*
|
||||||
|
* If the node is a mapping and no key matches index, a new key-value
|
||||||
|
* pair is added to the mapping. With sequences the index must be in
|
||||||
|
* range. This ensures behavior siilar to D arrays and associative
|
||||||
|
* arrays.
|
||||||
|
*
|
||||||
|
* Params: index = Index of the value to set.
|
||||||
|
*
|
||||||
|
* Throws: NodeException if the node is not a collection, index is out
|
||||||
|
* of range or if a non-integral index is used on a sequence node.
|
||||||
|
*/
|
||||||
|
void opIndexAssign(K, V)(V value, K index)
|
||||||
|
{
|
||||||
|
if(isSequence())
|
||||||
|
{
|
||||||
|
//This ensures K is integral.
|
||||||
|
checkSequenceIndex(index);
|
||||||
|
static if(isIntegral!K)
|
||||||
|
{
|
||||||
|
auto nodes = value_.get!(Node[]);
|
||||||
|
static if(is(V == Node)){nodes[index] = value;}
|
||||||
|
else {nodes[index] = Node(value);}
|
||||||
|
value_ = Value(nodes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
else if(isMapping())
|
||||||
|
{
|
||||||
|
auto idx = findPair(index);
|
||||||
|
if(idx < 0){add(index, value);}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto pairs = get!(Node.Pair[])();
|
||||||
|
static if(is(V == Node)){pairs[idx].value = value;}
|
||||||
|
else {pairs[idx].value = Node(value);}
|
||||||
|
value_ = Value(pairs);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NodeException("Trying to index a YAML node that is not a collection.",
|
||||||
|
startMark_);
|
||||||
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node([1, 2, 3, 4, 3]))
|
||||||
|
{
|
||||||
|
opIndexAssign(42, 3);
|
||||||
|
assert(length == 5);
|
||||||
|
assert(opIndex(3).get!int == 42);
|
||||||
|
}
|
||||||
|
with(Node(["1", "2", "3"], [4, 5, 6]))
|
||||||
|
{
|
||||||
|
opIndexAssign(42, "3");
|
||||||
|
opIndexAssign(123, 456);
|
||||||
|
assert(length == 4);
|
||||||
|
assert(opIndex("3").get!int == 42);
|
||||||
|
assert(opIndex(456).get!int == 123);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over a sequence, getting each element as T.
|
* Iterate over a sequence, getting each element as T.
|
||||||
*
|
*
|
||||||
|
@ -737,6 +798,199 @@ struct Node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an element to a sequence node.
|
||||||
|
*
|
||||||
|
* This method can only be called on sequence nodes.
|
||||||
|
*
|
||||||
|
* If value is a node, it is copied to the sequence directly. Otherwise
|
||||||
|
* value is converted to a node and then stored in the sequence.
|
||||||
|
*
|
||||||
|
* When emitting, all values in the sequence will be emitted. If using
|
||||||
|
* the !!set tag, the user needs to ensure that all elements in the
|
||||||
|
* sequence are unique, otherwise invalid YAML code will be emitted.
|
||||||
|
*
|
||||||
|
* Params: value = Value to add to the sequence.
|
||||||
|
*/
|
||||||
|
void add(T)(T value)
|
||||||
|
{
|
||||||
|
enforce(isSequence(),
|
||||||
|
new NodeException("Trying to add an element to a "
|
||||||
|
"non-sequence YAML node", startMark_));
|
||||||
|
|
||||||
|
auto nodes = get!(Node[])();
|
||||||
|
static if(is(T == Node)){nodes ~= value;}
|
||||||
|
else {nodes ~= Node(value);}
|
||||||
|
value_ = Value(nodes);
|
||||||
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node([1, 2, 3, 4]))
|
||||||
|
{
|
||||||
|
add(5.0f);
|
||||||
|
assert(opIndex(4).get!float == 5.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a key-value pair to a mapping node.
|
||||||
|
*
|
||||||
|
* This method can only be called on mapping nodes.
|
||||||
|
*
|
||||||
|
* If key and/or value is a node, it is copied to the mapping directly.
|
||||||
|
* Otherwise it is converted to a node and then stored in the mapping.
|
||||||
|
*
|
||||||
|
* It is possible to for the same key to be present more than once in a
|
||||||
|
* mapping. When emitting, all key-value pairs will be emitted.
|
||||||
|
* This is useful with the !!pairs tag, but will result in invalid YAML
|
||||||
|
* with !!map and !!omap tags.
|
||||||
|
*
|
||||||
|
* Params: key = Key to add.
|
||||||
|
* value = Value to add.
|
||||||
|
*/
|
||||||
|
void add(K, V)(K key, V value)
|
||||||
|
{
|
||||||
|
enforce(isMapping(),
|
||||||
|
new NodeException("Trying to add a key-value pair to a "
|
||||||
|
"non-mapping YAML node", startMark_));
|
||||||
|
|
||||||
|
auto pairs = get!(Node.Pair[])();
|
||||||
|
pairs ~= Pair(key, value);
|
||||||
|
value_ = Value(pairs);
|
||||||
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node([1, 2], [3, 4]))
|
||||||
|
{
|
||||||
|
add(5, "6");
|
||||||
|
assert(opIndex(5).get!string == "6");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove first (if any) occurence of a value in a collection.
|
||||||
|
*
|
||||||
|
* This method can only be called on collection nodes.
|
||||||
|
*
|
||||||
|
* If the node is a sequence, the first node matching value (including
|
||||||
|
* conversion, so e.g. "42" matches 42) is removed.
|
||||||
|
* If the node is a mapping, the first key-value pair where value_
|
||||||
|
* matches value is removed.
|
||||||
|
*
|
||||||
|
* Params: value = Value to remove.
|
||||||
|
*
|
||||||
|
* Throws: NodeException if the node is not a collection.
|
||||||
|
*/
|
||||||
|
void remove(T)(T value)
|
||||||
|
{
|
||||||
|
if(isSequence())
|
||||||
|
{
|
||||||
|
foreach(idx, ref elem; get!(Node[]))
|
||||||
|
{
|
||||||
|
if(elem.convertsTo!T && elem.get!T == value)
|
||||||
|
{
|
||||||
|
removeAt(idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(isMapping())
|
||||||
|
{
|
||||||
|
auto idx = findPair!(T, true)(value);
|
||||||
|
if(idx >= 0)
|
||||||
|
{
|
||||||
|
auto pairs = get!(Node.Pair[])();
|
||||||
|
copy(pairs[idx + 1 .. $], pairs[idx .. $ - 1]);
|
||||||
|
pairs.length = pairs.length - 1;
|
||||||
|
value_ = Value(pairs);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new NodeException("Trying to remove an element from a YAML node that "
|
||||||
|
"is not a collection.", startMark_);
|
||||||
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node([1, 2, 3, 4, 3]))
|
||||||
|
{
|
||||||
|
remove(3);
|
||||||
|
assert(length == 4);
|
||||||
|
assert(opIndex(2).get!int == 4);
|
||||||
|
assert(opIndex(3).get!int == 3);
|
||||||
|
}
|
||||||
|
with(Node(["1", "2", "3"], [4, 5, 6]))
|
||||||
|
{
|
||||||
|
remove(4);
|
||||||
|
assert(length == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove element at the specified index of a collection.
|
||||||
|
*
|
||||||
|
* This method can only be called on collection nodes.
|
||||||
|
*
|
||||||
|
* If the node is a sequence, index must be integral.
|
||||||
|
*
|
||||||
|
* If the node is a mapping, remove the first key-value pair where
|
||||||
|
* key matches index (including conversion, so e.g. "42" matches 42).
|
||||||
|
*
|
||||||
|
* If the node is a mapping and no key matches index, nothing is removed
|
||||||
|
* and no exception is thrown. This ensures behavior siilar to D arrays
|
||||||
|
* and associative arrays.
|
||||||
|
*
|
||||||
|
* Params: index = Index to remove at.
|
||||||
|
*
|
||||||
|
* Throws: NodeException if the node is not a collection, index is out
|
||||||
|
* of range or if a non-integral index is used on a sequence node.
|
||||||
|
*/
|
||||||
|
void removeAt(T)(T index)
|
||||||
|
{
|
||||||
|
if(isSequence())
|
||||||
|
{
|
||||||
|
//This ensures T is integral.
|
||||||
|
checkSequenceIndex(index);
|
||||||
|
static if(isIntegral!T)
|
||||||
|
{
|
||||||
|
auto nodes = value_.get!(Node[]);
|
||||||
|
copy(nodes[index + 1 .. $], nodes[index .. $ - 1]);
|
||||||
|
nodes.length = nodes.length - 1;
|
||||||
|
value_ = Value(nodes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
else if(isMapping())
|
||||||
|
{
|
||||||
|
auto idx = findPair(index);
|
||||||
|
if(idx >= 0)
|
||||||
|
{
|
||||||
|
auto pairs = get!(Node.Pair[])();
|
||||||
|
copy(pairs[idx + 1 .. $], pairs[idx .. $ - 1]);
|
||||||
|
pairs.length = pairs.length - 1;
|
||||||
|
value_ = Value(pairs);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new NodeException("Trying to remove an element from a YAML node that "
|
||||||
|
"is not a collection.", startMark_);
|
||||||
|
}
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
with(Node([1, 2, 3, 4, 3]))
|
||||||
|
{
|
||||||
|
removeAt(3);
|
||||||
|
assert(length == 4);
|
||||||
|
assert(opIndex(3).get!int == 3);
|
||||||
|
}
|
||||||
|
with(Node(["1", "2", "3"], [4, 5, 6]))
|
||||||
|
{
|
||||||
|
removeAt("2");
|
||||||
|
assert(length == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
package:
|
package:
|
||||||
/*
|
/*
|
||||||
* Construct a node from raw data.
|
* Construct a node from raw data.
|
||||||
|
@ -883,13 +1137,13 @@ struct Node
|
||||||
*/
|
*/
|
||||||
@property bool isType(T)() const {return value_.type is typeid(T);}
|
@property bool isType(T)() const {return value_.type is typeid(T);}
|
||||||
|
|
||||||
///Is the value an integer of some kind?
|
//Is the value an integer of some kind?
|
||||||
alias isType!long isInt;
|
alias isType!long isInt;
|
||||||
|
|
||||||
///Is the value a floating point number of some kind?
|
//Is the value a floating point number of some kind?
|
||||||
alias isType!real isFloat;
|
alias isType!real isFloat;
|
||||||
|
|
||||||
///Does given node have the same type as this node?
|
//Does given node have the same type as this node?
|
||||||
bool hasEqualType(ref Node node)
|
bool hasEqualType(ref Node node)
|
||||||
{
|
{
|
||||||
return value_.type is node.value_.type;
|
return value_.type is node.value_.type;
|
||||||
|
@ -913,6 +1167,53 @@ struct Node
|
||||||
else static if(isIntegral!T) {return isInt();}
|
else static if(isIntegral!T) {return isInt();}
|
||||||
else {return false;}
|
else {return false;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Get index of pair with key (or value, if value is true) matching index.
|
||||||
|
long findPair(T, bool value = false)(const ref T index)
|
||||||
|
{
|
||||||
|
auto pairs = get!(Node.Pair[])();
|
||||||
|
Node* node;
|
||||||
|
foreach(idx, ref pair; pairs)
|
||||||
|
{
|
||||||
|
static if(value){node = &pair.value;}
|
||||||
|
else{node = &pair.key;}
|
||||||
|
|
||||||
|
static if(is(T == Node))
|
||||||
|
{
|
||||||
|
if(*node == index){return idx;}
|
||||||
|
}
|
||||||
|
else static if(isFloatingPoint!T)
|
||||||
|
{
|
||||||
|
//Need to handle NaNs separately.
|
||||||
|
if((node.get!T == index) ||
|
||||||
|
(isFloat && isNaN(index) && isNaN(node.get!real)))
|
||||||
|
{
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(node.get!T == index){return idx;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Check if index is integral and in range.
|
||||||
|
void checkSequenceIndex(T)(T index)
|
||||||
|
{
|
||||||
|
static if(!isIntegral!T)
|
||||||
|
{
|
||||||
|
throw new NodeException("Indexing a YAML sequence with a non-integral type.",
|
||||||
|
startMark_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enforce(index >= 0 && index < value_.get!(Node[]).length,
|
||||||
|
new NodeException("Index to a YAML sequence out of range: "
|
||||||
|
~ to!string(index), startMark_));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
package:
|
package:
|
||||||
|
|
Loading…
Reference in a new issue