Added a random YAML generator to serve as an example and for
benchmarking.
This commit is contained in:
parent
7402d8f827
commit
1f2243190f
5
examples/yaml_gen/Makefile
Normal file
5
examples/yaml_gen/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
main:
|
||||||
|
dmd -w -I../../ -L-L../../ -L-ldyaml yaml_gen.d
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm yaml_gen yaml_gen.o
|
41
examples/yaml_gen/config.yaml
Normal file
41
examples/yaml_gen/config.yaml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
root-type: seq
|
||||||
|
documents: 2
|
||||||
|
complex-keys: false
|
||||||
|
min-nodes-per-document: 512
|
||||||
|
encoding: utf-32
|
||||||
|
indent: 4
|
||||||
|
text-width: 40
|
||||||
|
|
||||||
|
string:
|
||||||
|
probability: 10
|
||||||
|
range: {min: 1, max: 40, dist: cubic}
|
||||||
|
int:
|
||||||
|
probability: 10
|
||||||
|
range: {min: -10000000, max: 10000000, dist: linear}
|
||||||
|
float:
|
||||||
|
probability: 10
|
||||||
|
range: {min: -10000000.0, max: 10000000.0, dist: linear}
|
||||||
|
bool:
|
||||||
|
probability: 10
|
||||||
|
timestamp:
|
||||||
|
probability: 10
|
||||||
|
round-chance: 0.9
|
||||||
|
range: {min: 0, max: 1231200000000000000, dist: linear}
|
||||||
|
binary:
|
||||||
|
probability: 4
|
||||||
|
range: {min: 1, max: 400, dist: quadratic}
|
||||||
|
map:
|
||||||
|
probability: 2
|
||||||
|
range: {min: 1, max: 20, dist: cubic}
|
||||||
|
omap:
|
||||||
|
probability: 1
|
||||||
|
range: {min: 1, max: 20, dist: cubic}
|
||||||
|
pairs:
|
||||||
|
probability: 1
|
||||||
|
range: {min: 1, max: 20, dist: cubic}
|
||||||
|
seq:
|
||||||
|
probability: 2
|
||||||
|
range: {min: 1, max: 20, dist: cubic}
|
||||||
|
set:
|
||||||
|
probability: 1
|
||||||
|
range: {min: 1, max: 20, dist: cubic}
|
299
examples/yaml_gen/yaml_gen.d
Normal file
299
examples/yaml_gen/yaml_gen.d
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
|
||||||
|
import std.conv;
|
||||||
|
import std.datetime;
|
||||||
|
import std.math;
|
||||||
|
import std.random;
|
||||||
|
import std.stdio;
|
||||||
|
import std.string;
|
||||||
|
import yaml;
|
||||||
|
|
||||||
|
|
||||||
|
immutable alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
|
||||||
|
immutable digits = "0123456789";
|
||||||
|
|
||||||
|
Node config;
|
||||||
|
Node function(bool)[string] generators;
|
||||||
|
auto typesScalar = ["string", "int", "float", "bool", "timestamp", "binary"];
|
||||||
|
auto typesScalarKey = ["string", "int", "float", "timestamp"];
|
||||||
|
auto typesCollection = ["map","omap", "pairs", "seq", "set"];
|
||||||
|
ulong minNodesDocument;
|
||||||
|
ulong totalNodes;
|
||||||
|
|
||||||
|
static this()
|
||||||
|
{
|
||||||
|
generators["string"] = &genString;
|
||||||
|
generators["int"] = &genInt;
|
||||||
|
generators["float"] = &genFloat;
|
||||||
|
generators["bool"] = &genBool;
|
||||||
|
generators["timestamp"] = &genTimestamp;
|
||||||
|
generators["binary"] = &genBinary;
|
||||||
|
generators["map"] = &genMap;
|
||||||
|
generators["omap"] = &genOmap;
|
||||||
|
generators["pairs"] = &genPairs;
|
||||||
|
generators["seq"] = &genSeq;
|
||||||
|
generators["set"] = &genSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
real randomNormalized(in string distribution = "linear")
|
||||||
|
{
|
||||||
|
auto generator = Random(unpredictableSeed());
|
||||||
|
const r = uniform!"[]"(0.0L, 1.0L, generator);
|
||||||
|
switch(distribution)
|
||||||
|
{
|
||||||
|
case "linear":
|
||||||
|
return r;
|
||||||
|
case "quadratic":
|
||||||
|
return r * r;
|
||||||
|
case "cubic":
|
||||||
|
return r * r * r;
|
||||||
|
default:
|
||||||
|
writeln("Unknown random distribution: ", distribution,
|
||||||
|
", falling back to linear");
|
||||||
|
return randomNormalized("linear");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long randomLong(in long min, in long max, in string distribution = "linear")
|
||||||
|
{
|
||||||
|
return min + cast(long)round((max - min) * randomNormalized(distribution));
|
||||||
|
}
|
||||||
|
|
||||||
|
real randomReal(in real min, in real max, in string distribution = "linear")
|
||||||
|
{
|
||||||
|
return min + (max - min) * randomNormalized(distribution);
|
||||||
|
}
|
||||||
|
|
||||||
|
char randomChar(in string chars)
|
||||||
|
{
|
||||||
|
return chars[randomLong(0, chars.length - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
string randomType(string[] types)
|
||||||
|
{
|
||||||
|
auto probabilities = new uint[types.length];
|
||||||
|
foreach(index, type; types)
|
||||||
|
{
|
||||||
|
probabilities[index] = config[type]["probability"].get!uint;
|
||||||
|
}
|
||||||
|
return types[dice(probabilities)];
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genString(bool root = false)
|
||||||
|
{
|
||||||
|
auto range = config["string"]["range"];
|
||||||
|
|
||||||
|
const chars = randomLong(range["min"].get!uint, range["max"].get!uint,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
char[] result = new char[chars];
|
||||||
|
result[0] = randomChar(alphabet);
|
||||||
|
foreach(i; 1 .. chars)
|
||||||
|
{
|
||||||
|
result[i] = randomChar(alphabet ~ digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(cast(string)result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genInt(bool root = false)
|
||||||
|
{
|
||||||
|
auto range = config["int"]["range"];
|
||||||
|
|
||||||
|
const result = randomLong(range["min"].get!int, range["max"].get!int,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
return Node(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genFloat(bool root = false)
|
||||||
|
{
|
||||||
|
auto range = config["float"]["range"];
|
||||||
|
|
||||||
|
const result = randomReal(range["min"].get!real, range["max"].get!real,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
return Node(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genBool(bool root = false)
|
||||||
|
{
|
||||||
|
return Node([true, false][randomLong(0, 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genTimestamp(bool root = false)
|
||||||
|
{
|
||||||
|
auto range = config["timestamp"]["range"];
|
||||||
|
|
||||||
|
auto hnsecs = randomLong(range["min"].get!ulong, range["max"].get!ulong,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
if(randomNormalized() <= config["timestamp"]["round-chance"].get!real)
|
||||||
|
{
|
||||||
|
hnsecs -= hnsecs % 10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(SysTime(hnsecs));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genBinary(bool root = false)
|
||||||
|
{
|
||||||
|
auto range = config["binary"]["range"];
|
||||||
|
|
||||||
|
const bytes = randomLong(range["min"].get!uint, range["max"].get!uint,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
ubyte[] result = new ubyte[bytes];
|
||||||
|
foreach(i; 0 .. bytes)
|
||||||
|
{
|
||||||
|
result[i] = cast(ubyte)randomLong(0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node nodes(in bool root, Node range, in string tag, in bool set = false)
|
||||||
|
{
|
||||||
|
auto types = typesCollection ~ (set ? typesScalarKey : typesScalar);
|
||||||
|
|
||||||
|
Node[] nodes;
|
||||||
|
if(root)
|
||||||
|
{
|
||||||
|
while(!(totalNodes >= minNodesDocument))
|
||||||
|
{
|
||||||
|
nodes ~= generateNode(randomType(types));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const elems = randomLong(range["min"].get!uint, range["max"].get!uint,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
nodes = new Node[elems];
|
||||||
|
foreach(i; 0 .. elems)
|
||||||
|
{
|
||||||
|
nodes[i] = generateNode(randomType(types));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(nodes, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genSeq(bool root = false)
|
||||||
|
{
|
||||||
|
return nodes(root, config["seq"]["range"], "tag:yaml.org,2002:seq");
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genSet(bool root = false)
|
||||||
|
{
|
||||||
|
return nodes(root, config["seq"]["range"], "tag:yaml.org,2002:set", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node pairs(bool root, bool complex, Node range, string tag)
|
||||||
|
{
|
||||||
|
Node[] keys, values;
|
||||||
|
|
||||||
|
if(root)
|
||||||
|
{
|
||||||
|
while(!(totalNodes >= minNodesDocument))
|
||||||
|
{
|
||||||
|
keys ~= generateNode(randomType(typesScalarKey ~ (complex ? typesCollection : [])));
|
||||||
|
values ~= generateNode(randomType(typesScalar ~ typesCollection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const pairs = randomLong(range["min"].get!uint, range["max"].get!uint,
|
||||||
|
range["dist"].get!string);
|
||||||
|
|
||||||
|
keys = new Node[pairs];
|
||||||
|
values = new Node[pairs];
|
||||||
|
foreach(i; 0 .. pairs)
|
||||||
|
{
|
||||||
|
keys[i] = generateNode(randomType(typesScalarKey ~ (complex ? typesCollection : [])));
|
||||||
|
values[i] = generateNode(randomType(typesScalar ~ typesCollection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(keys, values, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genMap(bool root = false)
|
||||||
|
{
|
||||||
|
Node range = config["map"]["range"];
|
||||||
|
const complex = config["complex-keys"].get!bool;
|
||||||
|
|
||||||
|
return pairs(root, complex, range, "tag:yaml.org,2002:map");
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genOmap(bool root = false)
|
||||||
|
{
|
||||||
|
Node range = config["omap"]["range"];
|
||||||
|
const complex = config["complex-keys"].get!bool;
|
||||||
|
|
||||||
|
return pairs(root, complex, range, "tag:yaml.org,2002:omap");
|
||||||
|
}
|
||||||
|
|
||||||
|
Node genPairs(bool root = false)
|
||||||
|
{
|
||||||
|
Node range = config["pairs"]["range"];
|
||||||
|
const complex = config["complex-keys"].get!bool;
|
||||||
|
|
||||||
|
return pairs(root, complex, range, "tag:yaml.org,2002:pairs");
|
||||||
|
}
|
||||||
|
|
||||||
|
Node generateNode(in string type, bool root = false)
|
||||||
|
{
|
||||||
|
++totalNodes;
|
||||||
|
return generators[type](root);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node[] generate(in string configFileName)
|
||||||
|
{
|
||||||
|
config = Loader(configFileName).load();
|
||||||
|
|
||||||
|
minNodesDocument = config["min-nodes-per-document"].get!long;
|
||||||
|
|
||||||
|
Node[] result;
|
||||||
|
foreach(i; 0 .. config["documents"].get!uint)
|
||||||
|
{
|
||||||
|
result ~= generateNode(config["root-type"].get!string, true);
|
||||||
|
totalNodes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main(string[] args)
|
||||||
|
{
|
||||||
|
//Help message.
|
||||||
|
if(args.length == 1)
|
||||||
|
{
|
||||||
|
writeln("Usage: yaml_gen FILE [CONFIG_FILE]\n");
|
||||||
|
writeln("Generates a random YAML file and writes it to FILE.");
|
||||||
|
writeln("If provided, CONFIG_FILE overrides the default config file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string configFile = args.length >= 3 ? args[2] : "config.yaml";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Generate and dump the nodes.
|
||||||
|
Node[] generated = generate(configFile);
|
||||||
|
|
||||||
|
auto dumper = Dumper(args[1]);
|
||||||
|
auto encoding = config["encoding"];
|
||||||
|
dumper.encoding = encoding == "utf-16" ? Encoding.UTF_16:
|
||||||
|
encoding == "utf-32" ? Encoding.UTF_32:
|
||||||
|
Encoding.UTF_8;
|
||||||
|
|
||||||
|
dumper.indent = config["indent"].get!uint;
|
||||||
|
dumper.textWidth = config["text-width"].get!uint;
|
||||||
|
dumper.dump(generated);
|
||||||
|
}
|
||||||
|
catch(YAMLException e)
|
||||||
|
{
|
||||||
|
writeln("ERROR: ", e.msg);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue