gentyl
Version:
A Generator That You'll Love
383 lines (336 loc) • 13.8 kB
text/typescript
namespace Gentyl{
export namespace Util
{
export function identity(x){
return x
}
export function weightedChoice(weights:number[]){
var sum = weights.reduce(function(a,b){return a+b},0)
var cdfArray = weights.reduce(function(coll, next, i){
var v = (coll[i-1] || 0)+next/sum
return coll.concat([v])
},[])
var r = Math.random();
var i = 0;
//the cdf exceeds r increment
while(i < weights.length-1 && r > cdfArray[i]){i++}
return i
}
export function range(...args){
var beg, end, step
switch(args.length){
case 1:{
end = args[0]; beg=0; step=1
break;
}
case 2:{
end =args[1];beg=args[0];step=1
break;
}
case 3:{
end=args[2];beg=args[0];step=args[1]
break;
}
default:{
end=0;beg=0;step=1
break
}
}
var rng = []
if(beg > end && step < 0){
for(let i = beg; i > end; i+=step){
rng.push(i)
}
} else if (beg < end && step > 0){
for(let i = beg; i < end; i+=step){
rng.push(i)
}
} else {
throw new Error("invalid range parameters")
}
return rng;
}
export function translator(node, translation){
var translated
//array?
if(typeof(node) == "object" && !(node instanceof Array)){
translated = {};
for(var k in node){
var tval = translation[k]
if(typeof(tval)=="function"){
//rename to the function name with function value
translated[tval.name] = tval(node[k])
} if (typeof(tval)== "string"){
//rename the leaf
translated[tval] = node[k];
}else if (tval != undefined){
translated[k] = translator(node[k], tval)
}else {
//dont bother recurring if the translator wont come
translated[k] = node[k]
}
}
return translated
} else {
return node
}
}
export function melder(node1, node2, merge=function(a,b){return b}, concatArrays=false):any{
if(node1 == undefined){
return node2
}
if(node2 == undefined){
return node1
}
if(typeof(node1) != typeof(node2)){
var errmsg = "Expected melding nodes to be the same type \n"+
"type of node1: "+typeof(node1)+"\n"+
"type of node2: "+typeof(node2)+"\n"
throw TypeError(errmsg)
}
var melded;
if(node1 instanceof Array){
return concatArrays ? node1.concat(node2) : merge(node1,node2)
}else if(typeof(node1) == 'object'){
melded = {}
//in one or the other
for(var k in node1){
melded[k] = node1[k];
}
for(var q in node2){
melded[q] = node2[q];
}
//in both
for(var k in node1){
for(var q in node2){
if(k == q){
if(node1[k] == node2[k]){
melded[k] = node1[k] //co-contained
}else{
melded[k] = melder(node1[k], node2[k], merge, concatArrays) //collision
}
}
}
}
}
else{
// if they are not objects just take the second argument
melded = merge(node1,node2)
}
return melded
}
export function deeplyEquals(node1, node2, allowIdentical=true){
if(typeof(node1) != typeof(node2)){
return false // nodes not same type
}
else if (node1 instanceof Object){
if(node1 === node2 && !allowIdentical){
return false // identical object
}else{
for (var k in node1){
if(!(k in node2)){
return false; // key in node1 but node node2
}
}
for (var q in node2){
if(!(q in node1)){
return false;// key in node2 and not node1
}else if(!deeplyEquals(node1[q], node2[q], allowIdentical)){
return false; //recursive came up false.
}
}
return true; // no false flag
}
} else {
return (node1 === node2); ///primitive equality
}
}
export function deeplyEqualsThrow(node1, node2, derefstack, seen, allowIdentical=true){
var derefstack = derefstack || [];
var seen = seen || []
//circularity prevention
if(seen.indexOf(node1) || seen.indexOf(node2)){
return
}
if(typeof(node1) != typeof(node2)){
throw new Error(`nodes not same type, derefs: [${derefstack}]`)
}
else if (node1 instanceof Object){
if(node1 === node2 && !allowIdentical){
throw new Error(`identical object not replica, derefs:[${derefstack}]`)
}else{
for (var k in node1){
if(!(k in node2)){
throw new Error(`key ${k} in object1 but not object2, derefs:[${derefstack}]`)
}
}
for (var q in node2){
if(!(q in node1)){
throw new Error(`key ${k} in object2 but not object1, derefs:[${derefstack}]`)// key in node2 and not node1
}else{
deeplyEqualsThrow(node1[q], node2[q], derefstack.concat(q), allowIdentical)
}
}
return true; // no false flag
}
} else if(node1 !== node2){
throw new Error(`${node1} and ${node2} not equal, derefs:[${derefstack}]`)
}
}
export function isDeepReplica(node1, node2){
deeplyEquals(node1,node2,false)
}
export function isDeepReplicaThrow(node1, node2, derefstack){
deeplyEqualsThrow(node1, node2, derefstack, null, false)
}
//merge, when there is a conflict, neither is taken
export function softAssoc(from, onto){
for (var k in from){
onto[k] = melder(from[k], onto[k])
}
}
export function parassoc(from, onto){
for (var k in from){
onto[k] = melder(onto[k], from[k], function(a,b){
return [a,b]
}, true)
}
}
export function assoc(from, onto){
for (var k in from){
onto[k] = melder(onto[k], from[k])
}
}
export function deepCopy(thing){
return typeCaseSplitF(deepCopy, deepCopy)(thing)
}
export function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name];
});
});
}
export function isPrimative(thing){
return typeof(thing) !== 'object';
}
export function isVanillaObject(thing){
return thing instanceof Object && Object.prototype == Object.getPrototypeOf(thing)
}
export function isVanillaArray(thing){
return thing instanceof Array && Array.prototype == Object.getPrototypeOf(thing)
}
export function isTree(thing, stack=[]){
stack = stack.concat(thing)
function decirc(proposed){
if((stack.indexOf(proposed) === -1)){
return isTree(proposed, stack)
} else {
return false;
}
}
//recursively check for circularity and set the reduction to false.
return typeCaseSplitR(decirc, decirc, function(){return true})(thing, true, function(a,b,k){return a && b})
}
export function isVanillaTree(thing, stack=[]){
function decirc(proposed){
if((isVanillaObject(proposed) || isVanillaArray(proposed) && stack.indexOf(proposed) === -1)){
return isVanillaTree(proposed, stack.concat(proposed))
}else {
return false;
}
}
//recursively check for circularity and set the reduction to false.
return typeCaseSplitR(decirc, decirc, isPrimative)(thing, true, function(a,b,k){return a && b})
}
export function typeCaseSplitR(objectOrAllFunction, arrayFunc?, primativeFunc?){
var ofunc, afunc, pfunc;
if( primativeFunc == undefined && arrayFunc == undefined){
ofunc = objectOrAllFunction || identity;
afunc = objectOrAllFunction || identity;
pfunc = objectOrAllFunction || identity;
} else{
ofunc = objectOrAllFunction || identity;
afunc = arrayFunc || identity;
pfunc = primativeFunc || identity;
}
return function(inThing, initial=null, reductor=function(a,b,k){}){
var result = initial;
if(inThing instanceof Array){
for (var i = 0; i < inThing.length; i++){
var subBundle = inThing[i];
result = reductor(result, afunc(subBundle, i), i)
}
}else if(isVanillaObject(inThing)){
for (var k in inThing){
var subBundle = inThing[k];
result = reductor(result, ofunc(subBundle, k), k)
}
}else {
result = pfunc(inThing);
}
return result
}
}
export function typeCaseSplitF(objectOrAllFunction, arrayFunc?, primativeFunc?){
var ofunc, afunc, pfunc;
if( primativeFunc == undefined && arrayFunc == undefined){
ofunc = objectOrAllFunction || identity;
afunc = objectOrAllFunction || identity;
pfunc = objectOrAllFunction || identity;
} else{
ofunc = objectOrAllFunction || identity;
afunc = arrayFunc || identity;
pfunc = primativeFunc || identity;
}
return function(inThing){
var outThing;
if(inThing instanceof Array){
outThing = [];
outThing.length = inThing.length;
for (var i = 0; i < inThing.length; i++){
var subBundle = inThing[i];
outThing[i] = afunc(subBundle, i)
}
}else if(isVanillaObject(inThing)){
outThing = {}
for (var k in inThing){
var subBundle = inThing[k];
outThing[k] = ofunc(subBundle, k)
}
}else {
outThing = pfunc(inThing);
}
return outThing
}
}
export function typeCaseSplitM(objectOrAllFunction, arrayFunc?, primativeFunc?){
var ofunc, afunc, pfunc;
if( primativeFunc == undefined && arrayFunc == undefined){
ofunc = objectOrAllFunction || identity;
afunc = objectOrAllFunction || identity;
pfunc = objectOrAllFunction || identity;
} else{
ofunc = objectOrAllFunction || identity;
afunc = arrayFunc || identity;
pfunc = primativeFunc || identity;
}
return function(inThing){
if(inThing instanceof Array){
for (var i = 0; i < inThing.length; i++){
var subBundle = inThing[i];
inThing[i] = afunc(subBundle, i)
}
}else if(isVanillaObject){
for (var k in inThing){
var subBundle = inThing[k];
inThing[k] = ofunc(subBundle, k)
}
}else {
//wont modify primative
pfunc(inThing)
}
}
}
}
}