Updated Node for much more constness (unfortunately, quite some

code duplication as well). No longer need a custom Variant.
This commit is contained in:
Ferdinand Majerech 2011-10-30 18:12:02 +01:00
parent 508696584e
commit 8208e817de
13 changed files with 193 additions and 1624 deletions

View file

@ -29,7 +29,7 @@ links = ../index.html Documentation home
# Source files or patterns to ignore. Supports regexp syntax. # Source files or patterns to ignore. Supports regexp syntax.
# E.g; To ignore main.d and all source files in the test/ directory, # E.g; To ignore main.d and all source files in the test/ directory,
# you would use: "main.d test/*" # you would use: "main.d test/*"
ignore = test/*, examples/*, docsrc/*, autoddoc/*, yaml.d, unittest.d, cdc.d, dyaml/composer.d, dyaml/event.d, dyaml/parser.d, dyaml/reader.d, dyaml/scanner.d, dyaml/token.d, dyaml/util.d, dyaml/anchor.d, dyaml/emitter.d, dyaml/flags.d, dyaml/serializer.d, dyaml/sharedobject.d, dyaml/tag.d, dyaml/tagdirectives.d, dyaml/queue.d, dyaml/escapes.d, dyaml/fastcharsearch.d, dyaml/std/variant.d ignore = test/*, examples/*, docsrc/*, autoddoc/*, yaml.d, unittest.d, cdc.d, dyaml/composer.d, dyaml/event.d, dyaml/parser.d, dyaml/reader.d, dyaml/scanner.d, dyaml/token.d, dyaml/util.d, dyaml/anchor.d, dyaml/emitter.d, dyaml/flags.d, dyaml/serializer.d, dyaml/sharedobject.d, dyaml/tag.d, dyaml/tagdirectives.d, dyaml/queue.d, dyaml/escapes.d, dyaml/fastcharsearch.d
[DDOC] [DDOC]
# Command to use to generate the documentation. # Command to use to generate the documentation.

Binary file not shown.

View file

@ -52,6 +52,12 @@
</dt> </dt>
<dd><p>Null YAML type. Used in nodes with null values.</p> <dd><p>Null YAML type. Used in nodes with null values.</p>
<dl><dt class="d_decl">const string <a name="toString"></a><span class="ddoc_psymbol">toString</span>();
</dt>
<dd><p>Used for string conversion.</p>
</dd>
</dl>
</dd> </dd>
<dt class="d_decl">struct <a name="Node"></a><span class="ddoc_psymbol">Node</span>; <dt class="d_decl">struct <a name="Node"></a><span class="ddoc_psymbol">Node</span>;
</dt> </dt>
@ -80,7 +86,7 @@
<dd><p>Construct a Pair from two values. Will be converted to Nodes if needed.</p> <dd><p>Construct a Pair from two values. Will be converted to Nodes if needed.</p>
</dd> </dd>
<dt class="d_decl">bool <a name="equals"></a><span class="ddoc_psymbol">equals</span>(ref Pair <b>rhs</b>); <dt class="d_decl">const bool <a name="opEquals"></a><span class="ddoc_psymbol">opEquals</span>(ref const Pair <b>rhs</b>);
</dt> </dt>
<dd><p>Equality test with another Pair.</p> <dd><p>Equality test with another Pair.</p>
@ -263,7 +269,7 @@
<dd><p>Return <a name="tag"></a><span class="ddoc_psymbol">tag</span> of the node.</p> <dd><p>Return <a name="tag"></a><span class="ddoc_psymbol">tag</span> of the node.</p>
</dd> </dd>
<dt class="d_decl">bool <a name="opEquals"></a><span class="ddoc_psymbol">opEquals</span>(T)(ref T <b>rhs</b>); <dt class="d_decl">const bool <a name="opEquals"></a><span class="ddoc_psymbol">opEquals</span>(T)(ref const T <b>rhs</b>);
</dt> </dt>
<dd><p>Equality test. <dd><p>Equality test.
</p> </p>
@ -337,7 +343,7 @@
the value is out of range of requested type.</div> the value is out of range of requested type.</div>
</dd> </dd>
<dt class="d_decl">@property size_t <a name="length"></a><span class="ddoc_psymbol">length</span>(); <dt class="d_decl">const @property size_t <a name="length"></a><span class="ddoc_psymbol">length</span>();
</dt> </dt>
<dd><p>If this is a collection, return its length. <dd><p>If this is a collection, return its length.
</p> </p>

View file

@ -138,7 +138,7 @@ struct appears in Phobos.</p>
</div> </div>
<div class="footer"> <div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov. &copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011. Last updated on Oct 30, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div> </div>
</body> </body>

View file

@ -104,7 +104,7 @@
</div> </div>
<div class="footer"> <div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov. &copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011. Last updated on Oct 30, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div> </div>
</body> </body>

View file

@ -87,7 +87,7 @@
</div> </div>
<div class="footer"> <div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov. &copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011. Last updated on Oct 30, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div> </div>
</body> </body>

View file

@ -368,7 +368,7 @@ directory of the D:YAML package.</p>
</div> </div>
<div class="footer"> <div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov. &copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011. Last updated on Oct 30, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div> </div>
</body> </body>

View file

@ -237,7 +237,7 @@ example in the <tt class="docutils literal"><span class="pre">example/getting_st
</div> </div>
<div class="footer"> <div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov. &copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011. Last updated on Oct 30, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div> </div>
</body> </body>

View file

@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).</p>
</div> </div>
<div class="footer"> <div class="footer">
&copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov. &copy; Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
Last updated on Oct 29, 2011. Last updated on Oct 30, 2011.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
</div> </div>
</body> </body>

View file

@ -16,11 +16,12 @@ import std.conv;
import std.datetime; import std.datetime;
import std.exception; import std.exception;
import std.math; import std.math;
import std.range;
import std.stdio; import std.stdio;
import std.string; import std.string;
import std.traits; import std.traits;
import std.typecons; import std.typecons;
import dyaml.std.variant; import std.variant;
import dyaml.event; import dyaml.event;
import dyaml.exception; import dyaml.exception;
@ -73,7 +74,7 @@ package abstract class YAMLObject
protected: protected:
///Test for equality with another YAMLObject. ///Test for equality with another YAMLObject.
bool equals(YAMLObject rhs) {assert(false);} bool equals(const YAMLObject rhs) const {assert(false);}
} }
//Stores a user defined YAML data type. //Stores a user defined YAML data type.
@ -102,10 +103,10 @@ package class YAMLContainer(T) if (!Node.Value.allowed!T): YAMLObject
protected: protected:
//Test for equality with another YAMLObject. //Test for equality with another YAMLObject.
override bool equals(YAMLObject rhs) override bool equals(const YAMLObject rhs) const
{ {
if(rhs.type !is typeid(T)){return false;} if(rhs.type !is typeid(T)){return false;}
return cast(T)value_ == (cast(YAMLContainer)rhs).value_; return cast(T)value_ == (cast(const YAMLContainer)rhs).value_;
} }
private: private:
@ -134,7 +135,6 @@ struct Node
Node value; Node value;
public: public:
@disable bool opEquals(ref Pair);
@disable int opCmp(ref Pair); @disable int opCmp(ref Pair);
///Construct a Pair from two values. Will be converted to Nodes if needed. ///Construct a Pair from two values. Will be converted to Nodes if needed.
@ -147,10 +147,10 @@ struct Node
} }
///Equality test with another Pair. ///Equality test with another Pair.
bool equals(ref Pair rhs) bool opEquals(const ref Pair rhs) const
{ {
return equals_!true(rhs); return equals!true(rhs);
} }
private: private:
/* /*
@ -159,10 +159,10 @@ struct Node
* useTag determines whether or not we consider node tags * useTag determines whether or not we consider node tags
* in the test. * in the test.
*/ */
bool equals_(bool useTag)(ref Pair rhs) bool equals(bool useTag)(ref const(Pair) rhs) const
{ {
return key.equals!(Node, useTag)(rhs.key) && return key.equals!(useTag)(rhs.key) &&
value.equals!(Node, useTag)(rhs.value); value.equals!(useTag)(rhs.value);
} }
} }
@ -188,8 +188,6 @@ struct Node
public: public:
@disable int opCmp(ref Node); @disable int opCmp(ref Node);
@disable bool opEquals(T)(ref T) const if(is(T == const));
/** /**
* Construct a Node from a value. * Construct a Node from a value.
* *
@ -468,9 +466,9 @@ struct Node
* *
* Returns: true if equal, false otherwise. * Returns: true if equal, false otherwise.
*/ */
bool opEquals(T)(ref T rhs) if(!is(T == const)) bool opEquals(T)(const ref T rhs) const
{ {
return equals!(T, true)(rhs); return equals!true(rhs);
} }
///Shortcut for get(). ///Shortcut for get().
@ -517,37 +515,23 @@ struct Node
*/ */
@property T get(T)() if(!is(T == const)) @property T get(T)() if(!is(T == const))
{ {
if(isType!T) if(isType!T){return value_.get!T;}
{
return value_.get!T;
}
static if(!Value.allowed!T) ///Must go before others, as even string/int/etc could be stored in a YAMLObject.
static if(!Value.allowed!T) if(isUserType)
{ {
///Must go before others, as even string/int/etc could be stored in a YAMLObject. auto object = as!YAMLObject;
if(isUserType) if(object.type is typeid(T))
{ {
auto object = as!YAMLObject; return (cast(YAMLContainer!T)object).value_;
if(object.type is typeid(T))
{
return (cast(YAMLContainer!T)object).value_;
}
} }
throw new Error("Node has unexpected type: " ~ object.type.toString ~
". Expected: " ~ typeid(T).toString, startMark_);
} }
//If we're getting from a mapping and we're not getting Node.Pair[], //If we're getting from a mapping and we're not getting Node.Pair[],
//we're getting the default value. //we're getting the default value.
if(isMapping) if(isMapping){return this["="].as!T;}
{
return this["="].as!T;
}
void throwUnexpectedType()
{
//Can't get the value.
throw new Error("Node has unexpected type: " ~ type.toString ~
". Expected: " ~ typeid(T).toString, startMark_);
}
static if(isSomeString!T) static if(isSomeString!T)
{ {
@ -561,46 +545,79 @@ struct Node
throw new Error("Unable to convert node value to string", startMark_); throw new Error("Unable to convert node value to string", startMark_);
} }
} }
else static if(isFloatingPoint!T) else
{ {
///Can convert int to float. static if(isFloatingPoint!T)
if(isInt())
{ {
return to!T(value_.get!long); ///Can convert int to float.
if(isInt()) {return to!T(value_.get!(const long));}
else if(isFloat()){return to!T(value_.get!(const real));}
} }
else if(isFloat()) else static if(isIntegral!T) if(isInt())
{
return to!T(value_.get!real);
}
else
{
throwUnexpectedType();
assert(false);
}
}
else static if(isIntegral!T)
{
if(isInt())
{ {
const temp = value_.get!long; const temp = value_.get!(const long);
if(temp < T.min || temp > T.max) enforce(temp >= T.min && temp <= T.max,
{ new Error("Integer value of type " ~ typeid(T).toString ~
throw new Error("Integer value out of range of type " ~ " out of range. Value: " ~ to!string(temp), startMark_));
typeid(T).toString ~ "Value: " ~ to!string(temp),
startMark_);
}
return to!T(temp); return to!T(temp);
} }
else throw new Error("Node has unexpected type: " ~ type.toString ~
". Expected: " ~ typeid(T).toString, startMark_);
}
}
//Const version of get.
@property T get(T)() const if(is(T == const))
{
if(isType!T){return value_.get!T;}
///Must go before others, as even string/int/etc could be stored in a YAMLObject.
static if(!Value.allowed!T) if(isUserType)
{
auto object = as!(const YAMLObject);
if(object.type is typeid(T))
{ {
throwUnexpectedType(); return (cast(const YAMLContainer!T)object).value_;
assert(false); }
throw new Error("Node has unexpected type: " ~ object.type.toString ~
". Expected: " ~ typeid(T).toString, startMark_);
}
//If we're getting from a mapping and we're not getting Node.Pair[],
//we're getting the default value.
if(isMapping){return indexConst("=").as!T;}
static if(isSomeString!T)
{
//Try to convert to string.
try
{
//NOTE: We are casting away const here
return (cast(Value)value_).coerce!T();
}
catch(VariantException e)
{
throw new Error("Unable to convert node value to string", startMark_);
} }
} }
else else
{ {
throwUnexpectedType(); static if(isFloatingPoint!T)
assert(false); {
///Can convert int to float.
if(isInt()) {return to!T(value_.get!(const long));}
else if(isFloat()){return to!T(value_.get!(const real));}
}
else static if(isIntegral!T) if(isInt())
{
const temp = value_.get!(const long);
enforce(temp >= T.min && temp <= T.max,
new Error("Integer value of type " ~ typeid(T).toString ~
" out of range. Value: " ~ to!string(temp), startMark_));
return to!T(temp);
}
throw new Error("Node has unexpected type: " ~ type.toString ~
". Expected: " ~ typeid(T).toString, startMark_);
} }
} }
@ -643,13 +660,19 @@ struct Node
if(isSequence) if(isSequence)
{ {
checkSequenceIndex(index); checkSequenceIndex(index);
static if(isIntegral!T){return value_.get!(Node[])[index];} static if(isIntegral!T)
{
return cast(Node)value_.get!(Node[])[index];
}
assert(false); assert(false);
} }
else if(isMapping) else if(isMapping)
{ {
auto idx = findPair(index); auto idx = findPair(index);
if(idx >= 0){return as!(Pair[])[idx].value;} if(idx >= 0)
{
return cast(Node)value_.get!(Pair[])[idx].value;
}
string msg = "Mapping index not found" ~ (isSomeString!T ? ": " ~ to!string(index) : ""); string msg = "Mapping index not found" ~ (isSomeString!T ? ": " ~ to!string(index) : "");
throw new Error(msg, startMark_); throw new Error(msg, startMark_);
@ -1141,7 +1164,7 @@ struct Node
* *
* useTag determines whether or not to consider tags in node-node comparisons. * useTag determines whether or not to consider tags in node-node comparisons.
*/ */
bool equals(T, bool useTag)(ref T rhs) bool equals(bool useTag, T)(ref T rhs) const
{ {
static if(is(Unqual!T == Node)) static if(is(Unqual!T == Node))
{ {
@ -1155,55 +1178,50 @@ struct Node
{ {
return false; return false;
} }
if(isSequence)
static bool compareCollection(T)(const ref Node lhs, const ref Node rhs)
{ {
auto seq1 = as!(Node[]); const c1 = lhs.value_.get!(const T);
auto seq2 = rhs.as!(Node[]); const c2 = rhs.value_.get!(const T);
if(seq1 is seq2){return true;} if(c1 is c2){return true;}
if(seq1.length != seq2.length){return false;} if(c1.length != c2.length){return false;}
foreach(node; 0 .. seq1.length) foreach(ref i1, ref i2; lockstep(c1, c2))
{ {
if(!seq1[node].equals!(T, useTag)(seq2[node])){return false;} if(!i1.equals!useTag(i2)){return false;}
} }
return true; return true;
} }
if(isMapping)
static bool compare(T)(const ref Node lhs, const ref Node rhs)
{ {
auto map1 = as!(Node.Pair[]); return lhs.value_.get!(const T) == rhs.value_.get!(const T);
auto map2 = rhs.as!(Node.Pair[]);
if(map1 is map2){return true;}
if(map1.length != map2.length){return false;}
foreach(pair; 0 .. map1.length)
{
if(!map1[pair].equals_!useTag(map2[pair])){return false;}
}
return true;
} }
if(isScalar)
if(isSequence) {return compareCollection!(Node[])(this, rhs);}
else if(isMapping){return compareCollection!(Pair[])(this, rhs);}
else if(isString) {return compare!string(this, rhs);}
else if(isInt) {return compare!long(this, rhs);}
else if(isBool) {return compare!bool(this, rhs);}
else if(isBinary) {return compare!(ubyte[])(this, rhs);}
else if(isNull) {return true;}
else if(isFloat)
{ {
if(isUserType) const r1 = value_.get!(const real);
{ const r2 = rhs.value_.get!(const real);
if(!rhs.isUserType){return false;} return isNaN(r1) ? isNaN(r2)
return get!YAMLObject.equals(rhs.as!YAMLObject); : (r1 <= r2 + real.epsilon && r1 >= r2 - real.epsilon);
}
if(isFloat)
{
if(!rhs.isFloat){return false;}
real r1 = get!real;
real r2 = rhs.get!real;
bool equals(real r1, real r2)
{
return r1 <= r2 + real.epsilon && r1 >= r2 - real.epsilon;
}
if(isNaN(r1)){return isNaN(r2);}
return equals(r1, r2);
}
else
{
return value_ == rhs.value_;
}
} }
assert(false, "Unknown kind of node"); else if(isTime)
{
const t1 = value_.get!(const SysTime);
const t2 = rhs.value_.get!(const SysTime);
return t1 == t2;
}
else if(isUserType)
{
return value_.get!(const YAMLObject).equals(rhs.value_.get!(const YAMLObject));
}
assert(false, "Unknown kind of node (equality comparison) : " ~ type.toString);
} }
else else
{ {
@ -1265,15 +1283,27 @@ struct Node
@property bool isType(T)() const {return value_.type is typeid(Unqual!T);} @property bool isType(T)() const {return value_.type is typeid(Unqual!T);}
private: private:
//Is the value an integer of some kind? //Is the value a bool?
alias isType!bool isBool;
//Is the value a raw binary buffer?
alias isType!(ubyte[]) isBinary;
//Is the value an integer?
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?
alias isType!real isFloat; alias isType!real isFloat;
//Is the value a string of some kind? //Is the value a string?
alias isType!string isString; alias isType!string isString;
//Is the value a timestamp?
alias isType!SysTime isTime;
//Is the value a null value?
alias isType!YAMLNull isNull;
//Does given node have the same type as this node? //Does given node have the same type as this node?
bool hasEqualType(const ref Node node) const bool hasEqualType(const ref Node node) const
{ {
@ -1293,11 +1323,11 @@ struct Node
} }
//Get index of pair with key (or value, if value is true) matching index. //Get index of pair with key (or value, if value is true) matching index.
long findPair(T, bool value = false)(const ref T index) long findPair(T, bool value = false)(const ref T index) const
{ {
auto pairs = as!(Node.Pair[])(); const pairs = value_.get!(const Pair[])();
Node* node; const(Node)* node;
foreach(idx, ref pair; pairs) foreach(idx, ref const(Pair) pair; pairs)
{ {
static if(value){node = &pair.value;} static if(value){node = &pair.value;}
else{node = &pair.key;} else{node = &pair.key;}
@ -1317,7 +1347,7 @@ struct Node
} }
else else
{ {
try if(node.as!T == index){return idx;} try if(node.as!(const T) == index){return idx;}
catch(NodeException e) catch(NodeException e)
{ {
continue; continue;
@ -1341,6 +1371,32 @@ struct Node
startMark_)); startMark_));
} }
} }
//Const version of opIndex.
ref const(Node) indexConst(T)(T index) const
{
if(isSequence)
{
checkSequenceIndex(index);
static if(isIntegral!T)
{
return value_.get!(const Node[])[index];
}
assert(false);
}
else if(isMapping)
{
auto idx = findPair(index);
if(idx >= 0)
{
return value_.get!(const Pair[])[idx].value;
}
string msg = "Mapping index not found" ~ (isSomeString!T ? ": " ~ to!string(index) : "");
throw new Error(msg, startMark_);
}
throw new Error("Trying to index node that does not support indexing", startMark_);
}
} }
package: package:

File diff suppressed because it is too large Load diff

View file

@ -403,7 +403,7 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy)
size_t i = 0; size_t i = 0;
foreach(node; loader) foreach(node; loader)
{ {
if(!node.equals!(Node, false)(exp[i])) if(!node.equals!false(exp[i]))
{ {
if(verbose) if(verbose)
{ {

View file

@ -69,7 +69,7 @@ void testRepresenterTypes(bool verbose, string codeFilename)
assert(expectedNodes.length == readNodes.length); assert(expectedNodes.length == readNodes.length);
foreach(n; 0 .. expectedNodes.length) foreach(n; 0 .. expectedNodes.length)
{ {
assert(expectedNodes[n].equals!(Node, false)(readNodes[n])); assert(expectedNodes[n].equals!false(readNodes[n]));
} }
} }
} }