1
0
Fork 0

move globals.Hash to std.Hash

Add std.nas to loadpriority.xml and update related files
This commit is contained in:
Henning Stahlke 2020-07-01 14:46:47 +02:00 committed by James Turner
parent 78e9eff433
commit 4cb8a03e4b
10 changed files with 367 additions and 270 deletions

View file

@ -1,5 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# NOTE! This copyright does *not* cover user models that use these Nasal
# services by normal function calls - this is merely considered normal use
# of the code, and does *not* fall under the heading of "derived work."
#-------------------------------------------------------------------------------
# emesary.deb.nas - emesary debug helpers
# author: Henning Stahlke
# created: 06/2020
#-------------------------------------------------------------------------------
var _emesaryDebugN = props.getNode("/_debug/emesary/",1);
var _emesaryDebugEnableN = _emesaryDebugN.getNode("enabled",1);
@ -41,10 +48,11 @@ var __setup = func {
emesary.GlobalTransmitter.NotifyAll(debugNotification);
#add monitoring
var name = emesary._transmitters.getName();
emesary._transmitters.addCallback(func (k, v) {
emesary._transmitters.keys2props(_emesaryDebugN);
emesary._transmitters.keys2props(_emesaryDebugN.getNode(name, 1));
});
emesary._transmitters.keys2props(_emesaryDebugN);
emesary._transmitters.keys2props(_emesaryDebugN.getNode(name, 1));
}
settimer(__setup,0);

View file

@ -32,7 +32,7 @@
var __emesaryUniqueId = 14; # 0-15 are reserved, this way the global transmitter will be 15.
# add registry so we can find a transmitter by name in genericEmesaryGlobalTransmitterTransmit
var _transmitters = Hash.new("transmitters");
var _transmitters = std.Hash.new({}, "transmitters");
var _registerTransmitter = func (key, t) {
_transmitters.set(key, t);

View file

@ -188,55 +188,3 @@ settimer(func {
if(size(file) > 4 and substr(file, -4) == ".nas")
io.load_nasal(path ~ "/" ~ file, substr(file, 0, size(file) - 4));
}, 0);
# simple hash class for developers, allows to add callback on write
Hash = {
class_name: "Hash",
new: func(name) {
var obj = {
parents: [me],
name: name,
_h: {},
_callback: func,
};
return obj;
},
set: func (key, value) {
me._h[key] = value;
me._callback(key, value);
return me;
},
get: func (key) {
return me._h[key];
},
getName: func (key) {
return me.name;
},
getKeys: func () {
return keys(me._h);
},
keys2props: func (p) {
if (!isa(p, props.Node)) {
p = props.getNode(p,1);
}
p = p.getNode(me.name,1);
foreach (var key; keys(me._h)) {
p.getNode(key,1);
}
return;
},
# callback for set()
addCallback: func (f) {
if (isfunc(f)) {
me._callback = f;
}
return me;
},
};

View file

@ -34,6 +34,8 @@ string.nas <- gui.nas
io.nas <- gui.nas
gui.nas <- multiplayer.nas
multiplayer.nas <- view.nas
io.nas <- std.nas
geo.nas <- view.nas
view.nas <- dynamic_view.nas
-->
@ -45,6 +47,7 @@ geo.nas <- view.nas
<file>math.nas</file>
<file>string.nas</file>
<file>io.nas</file>
<file>std.nas</file>
<file>debug.nas</file>
<!-- stage 1 -->
<file>modules.nas</file>

21
Nasal/std.nas Normal file
View file

@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# NOTE! This copyright does *not* cover user models that use these Nasal
# services by normal function calls - this is merely considered normal use
# of the code, and does *not* fall under the heading of "derived work."
#-------------------------------------------------------------------------------
# std.nas - class loader for std lib
# author: Henning Stahlke
# created: 07/2020
#-------------------------------------------------------------------------------
var include_path = "Nasal/std/";
var files = [
"hash",
"string",
"vector",
];
foreach (var file; files) {
io.include(include_path~file~".nas");
}

195
Nasal/std.nut Normal file
View file

@ -0,0 +1,195 @@
#-------------------------------------------------------------------------------
# SPDX-License-Identifier: GPL-2.0-or-later
#-------------------------------------------------------------------------------
# std.nut - Nasal Unit Test for std.nas
# author: Henning Stahlke
# created: 06/2020
#-------------------------------------------------------------------------------
var setUp = func {
};
var tearDown = func {
};
#-- test std.Hash
var test_hash = func {
var hash = std.Hash.new({}, "testhash");
unitTest.assert(isa(hash, std.Hash), "std.Hash.new");
unitTest.assert(hash.getName() == "testhash" , "std.Hash.getName");
unitTest.assert(hash.set("foo", 42) == hash, "std.Hash.set");
unitTest.assert(hash.get("foo") == 42 , "std.Hash.get");
unitTest.assert(hash.contains("foo"), "std.Hash.contains");
hash.set("bar", 21);
unitTest.assert(isvec(hash.getKeys()), "std.Hash.getKeys isvec");
unitTest.assert(size(hash.getKeys()) == 2, "std.Hash.getKeys size");
unitTest.assert(hash.clear() == hash, "std.Hash.clear");
unitTest.assert(!hash.contains("foo"), "std.Hash.contains after clear");
unitTest.assert(size(hash.getKeys()) == 0, "std.Hash.getKeys after clear");
var cb_hash = {};
unitTest.assert(hash.addCallback(func(key, val) { cb_hash[key] = val; }) == hash,
"std.Hash.addCallback");
hash.set("foo", 21);
unitTest.assert(cb_hash["foo"] == 21, "std.addCallback worked");
hash.set("funct", func {});
hash.set("vec", [0,1,2]);
hash.set("hsh", {a:1, b:2});
var tmp = props.Node.new();
hash.keys2props(tmp);
unitTest.assert(isa(tmp.getNode("foo"), props.Node), "std.keys2props node ok");
var tmp = props.Node.new();
hash.hash2props(tmp);
unitTest.assert(tmp.getNode("foo").getValue() == 21, "std.hash2props ok");
}
#-- test std.String
var test_stoul = func {
unitTest.assert(std.stoul("123") == 123, "std.stoul 123");
unitTest.assert(std.stoul("A0", 16) == 160, "std.stoul 0xAF");
}
var test_string = func {
var x = std.String.new("FlightGear");
unitTest.assert(isa(x, std.String), "std.String.new");
unitTest.assert(x.compare("FlightGear"), "std.String.compare");
unitTest.assert(x.starts_with("Fli"), "std.String.starts_with");
unitTest.assert(!x.starts_with("Gear"), "std.String.starts_with");
unitTest.assert(x.find_first_of("i") == 2, "std.String.find_first_of");
unitTest.assert(x.find_first_of("i", 3) == -1, "std.String.find_first_of");
unitTest.assert(x.find_first_not_of("F") == 1, "std.String.find_first_not_of");
unitTest.assert(x.find_first_not_of("F", 2) == 2, "std.String.find_first_not_of");
unitTest.assert(x.find_first_not_of("F", 3) == 3, "std.String.find_first_not_of");
}
#-- test std.Vector
var test_vector = func {
var x = std.Vector.new();
unitTest.assert(isa(x, std.Vector), "std.Vector.new()");
unitTest.assert(x.size() == 0);
x = std.Vector.new(["x", "y"]);
unitTest.assert_equal(x.vector, ["x", "y"], "std.Vector.new(['x', 'y'])");
unitTest.assert(x.size() == 2, "std.Vector.new size 2");
x.clear();
unitTest.assert(isvec(x.vector) and x.size() == 0);
x = std.Vector.new([], "testvector");
var cb_vector = [];
unitTest.assert(x.getName() == "testvector" , "std.Vector.getName");
unitTest.assert(x.addCallback(func (index, item) {
if (index >= size(cb_vector)) append(cb_vector, item);
else cb_vector = cb_vector[0:index]~[item]~subvec(cb_vector, index);
}) == x, "std.Vector.addCallback");
# append():
x.append("a");
x.append("b");
x.append("c");
unitTest.assert_equal(x.vector, ["a", "b", "c"]);
unitTest.assert_equal(cb_vector, ["a", "b", "c"]);
unitTest.assert(x.size() == 3);
# extend():
x.extend(["d", "e"]);
unitTest.assert_equal(x.vector, ["a", "b", "c", "d", "e"]);
unitTest.assert(x.size() == 5);
# insert():
x.insert(2, "cc");
unitTest.assert_equal(x.vector, ["a", "b", "cc", "c", "d", "e"]);
unitTest.assert(x.size() == 6);
# pop():
unitTest.assert(x.pop(3), "c");
unitTest.assert_equal(x.vector, ["a", "b", "cc", "d", "e"]);
unitTest.assert(x.size() == 5);
unitTest.assert(x.pop(), "e");
unitTest.assert_equal(x.vector, ["a", "b", "cc", "d"]);
unitTest.assert(x.size() == 4);
# extend():
x.clear();
x.extend(["a", "b", "c", "d"]);
unitTest.assert_equal(x.vector, ["a", "b", "c", "d"]);
unitTest.assert(x.size() == 4);
# index():
unitTest.assert(x.index("c"), 2);
# contains():
unitTest.assert(x.contains("c"));
unitTest.assert(x.contains("e") == 0);
# remove():
x.remove("c");
unitTest.assert_equal(x.vector, ["a", "b", "d"]);
unitTest.assert(x.size() == 3);
# insert():
x.insert(0, "f");
unitTest.assert_equal(x.vector, ["f", "a", "b", "d"]);
unitTest.assert(x.size() == 4);
x.remove("f");
unitTest.assert_equal(x.vector, ["a", "b", "d"]);
x.insert(1, "f");
unitTest.assert_equal(x.vector, ["a", "f", "b", "d"]);
unitTest.assert(x.size() == 4);
x.remove("f");
unitTest.assert_equal(x.vector, ["a", "b", "d"]);
x.insert(2, "f");
unitTest.assert_equal(x.vector, ["a", "b", "f", "d"]);
x.remove("f");
unitTest.assert_equal(x.vector, ["a", "b", "d"]);
x.insert(3, "g");
unitTest.assert_equal(x.vector, ["a", "b", "d", "g"]);
x.remove("g");
x.insert(4, "g");
unitTest.assert_equal(x.vector, ["a", "b", "d", "g"]);
x.remove("g");
x.insert(-1, "h");
unitTest.assert_equal(x.vector, ["a", "b", "h", "d"]);
x.remove("h");
x.insert(-2, "h");
unitTest.assert_equal(x.vector, ["a", "h", "b", "d"]);
x.remove("h");
x.insert(-3, "h");
unitTest.assert_equal(x.vector, ["h", "a", "b", "d"]);
x.remove("h");
x.insert(-4, "h");
unitTest.assert_equal(x.vector, ["h", "a", "b", "d"]);
x.remove("h");
# pop():
unitTest.assert(x.pop(-1) == "d");
unitTest.assert_equal(x.vector, ["a", "b"]);
x.append("d");
unitTest.assert(x.pop(-2) == "b");
unitTest.assert_equal(x.vector, ["a", "d"]);
x.insert(1, "b");
unitTest.assert(x.pop(-3) == "a");
unitTest.assert_equal(x.vector, ["b", "d"]);
x.insert(0, "a");
unitTest.assert_equal(x.vector, ["a", "b", "d"]);
}

View file

@ -17,39 +17,50 @@
# services by normal function calls - this is merely considered normal use
# of the code, and does *not* fall under the heading of "derived work."
var min = func(a, b) { a < b ? a : b }
var max = func(a, b) { a > b ? a : b }
#load only once (via /Nasal/std.nas) not via C++ module loader
if (ishash(globals["std"]) and ishash(std["Vector"]))
return;
var Vector = {
new: func (vector=nil) {
new: func (vector=nil, name="") {
var m = {
parents: [Vector]
parents: [Vector],
name: name,
vector: [],
_callback: func,
};
if (vector == nil) {
vector = [];
if (isvec(vector)) {
m.vector = vector;
}
m.vector = vector;
return m;
},
# add callback for writes (insert() and append())
# will be called as f(index, item), compare insert() below
addCallback: func (f) {
if (isfunc(f)) {
me._callback = f;
return me;
}
return nil;
},
getName: func () {
return me.name;
},
size: func {
# Return the number of items in the vector
return size(me.vector);
},
clear: func {
# Remove all items from the vector, resulting in an empty vector
me.vector = [];
},
append: func (item) {
# Append the given item at the end of the vector
append(me.vector, item);
me._callback(me.size() - 1, item);
},
extend: func (other_vector) {
@ -73,11 +84,13 @@ var Vector = {
# insert(3, "f") => ["a", "b", "c", "f"]
# insert(-3, "g") => ["f", "a", "b", "c"]
index = min(index, me.size());
index = math.min(index, me.size());
if (index < 0) {
index = max(0, me.size() + index);
index = math.max(0, me.size() + index);
}
me.vector = subvec(me.vector, 0, index) ~ [item] ~ subvec(me.vector, index);
me._callback(index, item);
return me.vector;
},
pop: func (index=nil) {
@ -116,22 +129,14 @@ var Vector = {
index: func (item) {
# Return first index of the given item. Raises a ValueError
# if the item is not in the vector.
forindex (var index; me.vector) {
if (me.vector[index] == item) {
return index;
}
};
die("ValueError: item not in the vector");
var i = vecindex(me.vector, item);
if (i == nil) die("ValueError: item not in the vector");
return i;
},
contains: func (item) {
# Return true if the vector contains the item, false otherwise
var err = [];
call(Vector.index, [item], me, err);
return size(err) == 0;
return vecindex(me.vector, item) != nil;
},
remove: func (item) {

View file

@ -1,179 +0,0 @@
# Unit tests helpers
# TODO generalize (eg. move comparison operators somewhere global)
var eq = func(lhs, rhs)
{
if( typeof(lhs) != typeof(rhs) )
return 0;
if( typeof(lhs) == "scalar" )
return lhs == rhs;
if( typeof(lhs) == "vector" )
{
if( size(lhs) != size(rhs) )
return 0;
forindex(var i; lhs)
{
if( !eq(lhs[i], rhs[i]) )
return 0;
}
return 1;
}
return lhs == rhs;
}
var print_fail = func(msg)
{
var c = caller(1); # [namespace, func, file, line]
die(c[2] ~ "(" ~ c[3] ~ "): error: " ~ msg);
}
var REQUIRE_EQUAL = func(lhs, rhs)
{
if( !eq(lhs, rhs) )
print_fail( "check failed [" ~ debug.string(lhs, 0)
~ " != "
~ debug.string(rhs, 0)
~ "]" );
}
# @param fn Function for testing
# @param ex (Part of) the expection thrown (with die())
var REQUIRE_THROW = func(fn, ex)
{
call(fn, nil, var err = []);
var err_msg = "exception " ~ ex ~ " expected";
if( size(err) )
{
if( err[0].starts_with(ex ~ ": ") )
return;
err_msg ~= " (got '" ~ err[0] ~ "')";
}
print_fail(err_msg);
}
var x = std.Vector.new();
REQUIRE_EQUAL(x.size(), 0);
x = std.Vector.new(["x", "y"]);
REQUIRE_EQUAL(x.vector, ["x", "y"]);
REQUIRE_EQUAL(x.size(), 2);
x.clear();
REQUIRE_EQUAL(x.vector, []);
REQUIRE_EQUAL(x.size(), 0);
# append():
x.append("a");
x.append("b");
x.append("c");
REQUIRE_EQUAL(x.vector, ["a", "b", "c"]);
REQUIRE_EQUAL(x.size(), 3);
# extend():
x.extend(["d", "e"]);
REQUIRE_EQUAL(x.vector, ["a", "b", "c", "d", "e"]);
REQUIRE_EQUAL(x.size(), 5);
# insert():
x.insert(2, "cc");
REQUIRE_EQUAL(x.vector, ["a", "b", "cc", "c", "d", "e"]);
REQUIRE_EQUAL(x.size(), 6);
# pop():
REQUIRE_EQUAL(x.pop(3), "c");
REQUIRE_EQUAL(x.vector, ["a", "b", "cc", "d", "e"]);
REQUIRE_EQUAL(x.size(), 5);
REQUIRE_EQUAL(x.pop(), "e");
REQUIRE_EQUAL(x.vector, ["a", "b", "cc", "d"]);
REQUIRE_EQUAL(x.size(), 4);
# clear():
x.clear();
REQUIRE_EQUAL(x.vector, []);
REQUIRE_EQUAL(x.size(), 0);
# extend():
x.extend(["a", "b", "c", "d"]);
REQUIRE_EQUAL(x.vector, ["a", "b", "c", "d"]);
REQUIRE_EQUAL(x.size(), 4);
# index():
REQUIRE_EQUAL(x.index("c"), 2);
# contains():
REQUIRE_EQUAL(x.contains("c"), 1);
REQUIRE_EQUAL(x.contains("e"), 0);
# remove():
x.remove("c");
REQUIRE_EQUAL(x.vector, ["a", "b", "d"]);
REQUIRE_EQUAL(x.size(), 3);
# insert():
x.insert(0, "f");
REQUIRE_EQUAL(x.vector, ["f", "a", "b", "d"]);
REQUIRE_EQUAL(x.size(), 4);
x.remove("f");
REQUIRE_EQUAL(x.vector, ["a", "b", "d"]);
x.insert(1, "f");
REQUIRE_EQUAL(x.vector, ["a", "f", "b", "d"]);
REQUIRE_EQUAL(x.size(), 4);
x.remove("f");
REQUIRE_EQUAL(x.vector, ["a", "b", "d"]);
x.insert(2, "f");
REQUIRE_EQUAL(x.vector, ["a", "b", "f", "d"]);
x.remove("f");
REQUIRE_EQUAL(x.vector, ["a", "b", "d"]);
x.insert(3, "g");
REQUIRE_EQUAL(x.vector, ["a", "b", "d", "g"]);
x.remove("g");
x.insert(4, "g");
REQUIRE_EQUAL(x.vector, ["a", "b", "d", "g"]);
x.remove("g");
x.insert(-1, "h");
REQUIRE_EQUAL(x.vector, ["a", "b", "h", "d"]);
x.remove("h");
x.insert(-2, "h");
REQUIRE_EQUAL(x.vector, ["a", "h", "b", "d"]);
x.remove("h");
x.insert(-3, "h");
REQUIRE_EQUAL(x.vector, ["h", "a", "b", "d"]);
x.remove("h");
x.insert(-4, "h");
REQUIRE_EQUAL(x.vector, ["h", "a", "b", "d"]);
x.remove("h");
# pop():
REQUIRE_EQUAL(x.pop(-1), "d");
REQUIRE_EQUAL(x.vector, ["a", "b"]);
x.append("d");
REQUIRE_EQUAL(x.pop(-2), "b");
REQUIRE_EQUAL(x.vector, ["a", "d"]);
x.insert(1, "b");
REQUIRE_EQUAL(x.pop(-3), "a");
REQUIRE_EQUAL(x.vector, ["b", "d"]);
x.insert(0, "a");
REQUIRE_EQUAL(x.vector, ["a", "b", "d"]);
# Exceptions (should fail)
REQUIRE_THROW(func x.pop(-4), "IndexError");
REQUIRE_THROW(func x.pop(3), "IndexError");
REQUIRE_THROW(func x.remove("e"), "ValueError");

86
Nasal/std/hash.nas Normal file
View file

@ -0,0 +1,86 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# NOTE! This copyright does *not* cover user models that use these Nasal
# services by normal function calls - this is merely considered normal use
# of the code, and does *not* fall under the heading of "derived work."
#-------------------------------------------------------------------------------
# hash.nas - simple hash class for development, allows to add callback on write
# author: Henning Stahlke
# created: 07/2020
#-------------------------------------------------------------------------------
#load only once (via /Nasal/std.nas) not via C++ module loader
if (ishash(globals["std"]) and ishash(std["Hash"]))
return;
Hash = {
new: func(hash=nil, name="") {
var obj = {
parents: [me],
name: name,
_h: {},
_callback: func,
};
if (ishash(hash))
obj._h = hash;
return obj;
},
set: func (key, value) {
me._h[key] = value;
me._callback(key, value);
return me;
},
get: func (key) {
return me._h[key];
},
clear: func() {
me._h = {};
return me;
},
contains: func(key) {
return contains(me._h, key);
},
getName: func () {
return me.name;
},
getKeys: func () {
return keys(me._h);
},
# export keys to props p/<keys>
# p: root property path or props.Node object
keys2props: func (p) {
if (!isa(p, props.Node)) {
p = props.getNode(p, 1);
}
foreach (var key; keys(me._h)) {
p.getNode(key, 1);
}
return me;
},
# export hash to props p/<key>=<value>
# p: root property path or props.Node object
hash2props: func (p) {
if (!isa(p, props.Node)) {
p = props.getNode(p, 1);
}
p.setValues(me._h);
return me;
},
# callback for set()
addCallback: func (f) {
if (isfunc(f)) {
me._callback = f;
return me;
}
return nil;
},
};

View file

@ -9,15 +9,15 @@
#
# Copyright (C) 2012-2013 by Thomas Geymayer
#load only once (via /Nasal/std.nas) not via C++ module loader
if (ishash(globals["std"]) and ishash(std["String"]))
return;
# capture global string
var _string = string;
var string = {
var String = {
# public:
new: func(str)
{
return { parents: [string], _str: str };
return { parents: [String], _str: str };
},
# compare(s)
# compare(pos, n, s)
@ -56,6 +56,9 @@ var string = {
return 0;
return 1;
},
# returns index (zero based) of first occurrence of s
# searching from pos
find_first_of: func(s, pos = 0)
{
return me._find(pos, size(me._str), s, 1);
@ -101,6 +104,13 @@ var string = {
}
};
# for backward compatibility
var string = {parents: [String]};
string.new = func {
logprint(LOG_ALERT, "Deprecated use of std.string, please use std.String instead.");
return String.new(arg[0]);
}
# converts a string to an unsigned integer
var stoul = func(str, base = 10)
{
@ -109,10 +119,10 @@ var stoul = func(str, base = 10)
{
var c = str[pos];
if( _string.isdigit(c) )
if( globals.string.isdigit(c) )
var digval = c - `0`;
else if( _string.isalpha(c) )
var digval = _string.toupper(c) - `A` + 10;
else if( globals.string.isalpha(c) )
var digval = globals.string.toupper(c) - `A` + 10;
else
break;